diff --git a/sleepyhead/SleepLib/common.cpp b/sleepyhead/SleepLib/common.cpp index 502af0ee..04b02df6 100644 --- a/sleepyhead/SleepLib/common.cpp +++ b/sleepyhead/SleepLib/common.cpp @@ -115,6 +115,8 @@ QString STR_UNIT_Minutes; QString STR_UNIT_Seconds; QString STR_UNIT_BPM; // Beats per Minute QString STR_UNIT_LPM; // Litres per Minute +QString STR_UNIT_ml; // MilliLitres +QString STR_UNIT_Litres; QString STR_UNIT_Hz; QString STR_UNIT_EventsPerHour; QString STR_UNIT_BreathsPerMinute; @@ -301,6 +303,8 @@ void initializeStrings() STR_UNIT_Hz = QObject::tr("Hz"); // Hertz STR_UNIT_BPM = QObject::tr("bpm"); // Beats per Minute STR_UNIT_LPM = QObject::tr("L/min"); // Litres per Minute + STR_UNIT_Litres = QObject::tr("Litres"); + STR_UNIT_ml = QObject::tr("ml"); // millilitres STR_UNIT_BreathsPerMinute = QObject::tr("Breaths/min"); // Breaths per minute STR_UNIT_Unknown = QObject::tr("??"); STR_UNIT_Ratio = QObject::tr("ratio"); diff --git a/sleepyhead/SleepLib/common.h b/sleepyhead/SleepLib/common.h index e74cefe9..36ce08bd 100644 --- a/sleepyhead/SleepLib/common.h +++ b/sleepyhead/SleepLib/common.h @@ -131,6 +131,8 @@ extern QString STR_UNIT_Minutes; extern QString STR_UNIT_Seconds; extern QString STR_UNIT_BPM; // Beats per Minute extern QString STR_UNIT_LPM; // Litres per Minute +extern QString STR_UNIT_ml; // millilitres +extern QString STR_UNIT_Litres; extern QString STR_UNIT_Hz; extern QString STR_UNIT_EventsPerHour; extern QString STR_UNIT_Percentage; diff --git a/sleepyhead/SleepLib/profiles.cpp b/sleepyhead/SleepLib/profiles.cpp index 88caea95..15b3ee1c 100644 --- a/sleepyhead/SleepLib/profiles.cpp +++ b/sleepyhead/SleepLib/profiles.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -108,40 +109,127 @@ bool Profile::Open(QString filename) return b; } + +// Borrowed from QtCreator (http://stackoverflow.com/questions/3490336/how-to-reveal-in-finder-or-show-in-explorer-with-qt) +void showInGraphicalShell(const QString &pathIn) +{ + QWidget * parent = NULL; + + // Mac, Windows support folder or file. +#if defined(Q_OS_WIN) + const QString explorer = Environment::systemEnvironment().searchInPath(QLatin1String("explorer.exe")); + if (explorer.isEmpty()) { + QMessageBox::warning(parent, + tr("Launching Windows Explorer failed"), + tr("Could not find explorer.exe in path to launch Windows Explorer.")); + return; + } + QString param; + if (!QFileInfo(pathIn).isDir()) + param = QLatin1String("/select,"); + param += QDir::toNativeSeparators(pathIn); + QProcess::startDetached(explorer, QStringList(param)); +#elif defined(Q_OS_MAC) + Q_UNUSED(parent) + QStringList scriptArgs; + scriptArgs << QLatin1String("-e") + << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"") + .arg(pathIn); + QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs); + scriptArgs.clear(); + scriptArgs << QLatin1String("-e") + << QLatin1String("tell application \"Finder\" to activate"); + QProcess::execute("/usr/bin/osascript", scriptArgs); +#else + // we cannot select a file here, because no file browser really supports it... + const QFileInfo fileInfo(pathIn); + const QString folder = fileInfo.absoluteFilePath(); + const QString app = Utils::UnixUtils::fileBrowser(Core::ICore::instance()->settings()); + QProcess browserProc; + const QString browserArgs = Utils::UnixUtils::substituteFileBrowserParameters(app, folder); + if (debug) + qDebug() << browserArgs; + bool success = browserProc.startDetached(browserArgs); + const QString error = QString::fromLocal8Bit(browserProc.readAllStandardError()); + success = success && error.isEmpty(); + if (!success) { + QMessageBox::warning(NULL,STR_MessageBox_Error, "Could not find the file browser for your system, you will have to find your profile directory yourself."+"\n\n"+error, QMessageBox::Ok); +// showGraphicalShellError(parent, app, error); + } +#endif +} + void Profile::DataFormatError(Machine *m) { - QString msg = - QObject::tr("Software changes have been made that require the reimporting of the following machines data:\n\n"); - msg = msg + m->properties[STR_PROP_Brand] + " " + m->properties[STR_PROP_Model] + " " + - m->properties[STR_PROP_Serial] + "\n\n"; - msg = msg + - QObject::tr("I can automatically purge this data for you, or you can cancel now and continue to run in a previous version.\n\n"); - msg = msg + - QObject::tr("Would you like me to purge this data this for you so you can run the new version?"); + QString msg; - if (QMessageBox::warning(nullptr, - QObject::tr("Machine Database Changes"), - msg, - QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes) == QMessageBox::Yes) { + msg = ""+QObject::tr("SleepyHead (%1) needs to upgrade its database for %2 %3 %4"). + arg(FullVersionString). + arg(m->properties[STR_PROP_Brand]).arg(m->properties[STR_PROP_Model]).arg(m->properties[STR_PROP_Serial]) + + "

"; + + bool backups = false; + if (p_profile->session->backupCardData() && m->properties.contains(STR_PROP_BackupPath)) { + QDir dir(Get(m->properties[STR_PROP_BackupPath])); + if (dir.count() > 0) backups = true; + } + + if (backups) { + msg = msg + QObject::tr("SleepyHead maintains a backup of your devices data card that it uses for this purpose.")+ "

"; + msg = msg + QObject::tr("Your old machine data should be regenerated provided this backup feature has not been disabled in preferences during a previous data import.") + "

"; + backups = true; + } else { + msg = msg + QObject::tr("SleepyHead does not yet have an automatic card backup capabilities for this device.") + "

"; + msg = msg + QObject::tr("This means you will need to import this machine data again afterwards from your own backups or data card.") + "

"; + } + + msg += ""+QObject::tr("Important:")+" "+QObject::tr("Once you upgrade, you can not use this profile with the previous version anymore.")+"

"+ + QObject::tr("If you are concerned, click No to exit, and backup your profile manually, before starting SleepyHead again.")+ "

"; + msg = msg + ""+QObject::tr("Are you ready to upgrade, so you can run the new version of SleepyHead?")+""; + QMessageBox * question = new QMessageBox(QMessageBox::Warning, QObject::tr("Machine Database Changes"), msg, QMessageBox::Yes | QMessageBox::No); + question->setDefaultButton(QMessageBox::Yes); + + QFont font("Sans Serif", 11, QFont::Normal); + + question->setFont(font); + + if (question->exec() == QMessageBox::Yes) { if (!m->Purge(3478216)) { - // Do not copy this line without thinking.. You will be eaten by a Grue if you do - + // Purge failed.. probably a permissions error.. let the user deal with it. QMessageBox::critical(nullptr, STR_MessageBox_Error, QObject::tr("Sorry, the purge operation failed, which means this version of SleepyHead can't start.")+"\n\n"+ QObject::tr("The machine data folder needs to be removed manually.")+"\n\n"+ QObject::tr("This folder currently resides at the following location:")+"\n\n"+ - QDir::toNativeSeparators(PREF[STR_GEN_DataFolder].toString()), QMessageBox::Ok); + QDir::toNativeSeparators(Get(p_preferences[STR_GEN_DataFolder].toString())), QMessageBox::Ok); QApplication::exit(-1); } // Note: I deliberately haven't added a Profile help for this - PROFILE.p_preferences[STR_PREF_ReimportBackup] = true; + if (backups) { + mainwin->importCPAP(Get(m->properties[STR_PROP_BackupPath]), QObject::tr("Rebuilding from %1 Backup").arg(m->properties[STR_PROP_Brand])); + } else { + QMessageBox::information(nullptr, STR_MessageBox_Information, + QObject::tr("SleepyHead will now start the import wizard so you can reinstall your %1 data.").arg(m->properties[STR_PROP_Brand]) + ,QMessageBox::Ok, QMessageBox::Ok); + mainwin->startImportDialog(); + } PROFILE.Save(); + delete question; + } else { + delete question; + QMessageBox::information(nullptr, STR_MessageBox_Information, + QObject::tr("SleepyHead will now exit, then (attempt to) launch your computers file manager so you can manually back your profile up:")+"\n\n"+ + QDir::toNativeSeparators(Get(p_preferences[STR_GEN_DataFolder].toString()))+"\n\n"+ + QObject::tr("Use your file manager to make a copy of your profile directory, then afterwards, restart Sleepyhead and complete the upgrade process.") + , QMessageBox::Ok, QMessageBox::Ok); + + showInGraphicalShell(Get(p_preferences[STR_GEN_DataFolder].toString())); QApplication::exit(-1); } + return; } @@ -600,7 +688,7 @@ void Scan() QFileInfo fi = list.at(i); QString npath = fi.canonicalFilePath(); Profile *prof = new Profile(npath); -// prof->Open(); // Read it's XML file.. + profiles[fi.fileName()] = prof; } diff --git a/sleepyhead/SleepLib/schema.cpp b/sleepyhead/SleepLib/schema.cpp index 58d79e0b..1ebbf3be 100644 --- a/sleepyhead/SleepLib/schema.cpp +++ b/sleepyhead/SleepLib/schema.cpp @@ -289,7 +289,7 @@ void init() schema::channel.add(GRP_CPAP, new Channel(CPAP_TidalVolume = 0x1103, WAVEFORM, SESSION, "TidalVolume", QObject::tr("Tidal Volume"), QObject::tr("Amount of air displaced per breath"), QObject::tr("Tidal Volume"), - STR_UNIT_LPM, DEFAULT, QColor("magenta"))); + STR_UNIT_ml, DEFAULT, QColor("magenta"))); schema::channel.add(GRP_CPAP, new Channel(CPAP_Snore = 0x1104, WAVEFORM, SESSION, "Snore", QObject::tr("Snore"), diff --git a/sleepyhead/SleepLib/session.cpp b/sleepyhead/SleepLib/session.cpp index d4c993ff..a59a362a 100644 --- a/sleepyhead/SleepLib/session.cpp +++ b/sleepyhead/SleepLib/session.cpp @@ -996,6 +996,12 @@ void Session::setEnabled(bool b) } +QString Session::dimension(ChannelID id) +{ + // Cheat for now + return schema::channel[id].units(); +} + EventDataType Session::Min(ChannelID id) { QHash::iterator i = m_min.find(id); diff --git a/sleepyhead/SleepLib/session.h b/sleepyhead/SleepLib/session.h index 4f2d8ef5..27d88b1c 100644 --- a/sleepyhead/SleepLib/session.h +++ b/sleepyhead/SleepLib/session.h @@ -135,6 +135,9 @@ class Session return s_changed; } + //! \brief Return the unit type string used by events of supplied channel + QString dimension(ChannelID); + //! \brief Contains all the EventLists, indexed by ChannelID QHash > eventlist; diff --git a/sleepyhead/mainwindow.h b/sleepyhead/mainwindow.h index 052e6458..fc7ef29c 100644 --- a/sleepyhead/mainwindow.h +++ b/sleepyhead/mainwindow.h @@ -139,7 +139,9 @@ class MainWindow : public QMainWindow //! \brief Internal function to set Records Box html from statistics module void setRecBoxHTML(QString html); + int importCPAP(const QString &path, const QString &message); + void startImportDialog() { on_action_Import_Data_triggered(); } public slots: //! \brief Recalculate all event summaries and flags @@ -315,7 +317,6 @@ class MainWindow : public QMainWindow void logMessage(QString msg); private: - int importCPAP(const QString &path, const QString &message); void importCPAPBackups(); void finishCPAPImport(); QStringList detectCPAPCards(); diff --git a/sleepyhead/profileselect.cpp b/sleepyhead/profileselect.cpp index a1b2d5a3..0b959d25 100644 --- a/sleepyhead/profileselect.cpp +++ b/sleepyhead/profileselect.cpp @@ -297,6 +297,10 @@ void ProfileSelect::on_listView_activated(const QModelIndex &index) if (!profile) { return; } if (!profile->isOpen()) { profile->Open(); + // Do this in case user renames the directory (otherwise it won't load) + // Essentially makes the folder name the user name, but whatever.. + // TODO: Change the profile editor one day to make it rename the actual folder + profile->p_preferences[STR_UI_UserName] = name; } if (!profile->user->hasPassword()) {