Restructure Day object to allow for multiple machine sessions

This commit is contained in:
Mark Watkins 2014-08-21 03:17:13 +10:00
parent ba8b8f12fa
commit e27232423e
19 changed files with 798 additions and 621 deletions

View File

@ -48,17 +48,18 @@ void MinutesAtPressure::SetDay(Day *day)
Layer::SetDay(day); Layer::SetDay(day);
// look at session summaryValues. // look at session summaryValues.
if (day) { Machine * cpap = nullptr;
if (day) cpap = day->machine(MT_CPAP);
if (cpap) {
QList<Session *>::iterator sit; QList<Session *>::iterator sit;
EventDataType minpressure = 40; EventDataType minpressure = 40;
EventDataType maxpressure = 0; EventDataType maxpressure = 0;
Machine * mach = day->machine;
QMap<QDate, Day *>::iterator it; QMap<QDate, Day *>::iterator it;
QMap<QDate, Day *>::iterator day_end = mach->day.end(); QMap<QDate, Day *>::iterator day_end = cpap->day.end();
// look at overall pressure ranges and find the max // look at overall pressure ranges and find the max
for (it = mach->day.begin(); it != day_end; ++it) { for (it = cpap->day.begin(); it != day_end; ++it) {
Day * d = it.value(); Day * d = it.value();
QList<Session *>::iterator sess_end = d->end(); QList<Session *>::iterator sess_end = d->end();
for (sit = d->begin(); sit != sess_end; ++sit) { for (sit = d->begin(); sit != sess_end; ++sit) {

View File

@ -124,7 +124,7 @@ void SummaryChart::SetDay(Day * nullday)
bool first = true; bool first = true;
// For each day in the main profile daylist // For each day in the main profile daylist
QMap<QDate, QList<Day *> >::iterator d; QMap<QDate, Day *>::iterator d;
for (d = p_profile->daylist.begin(); d != p_profile->daylist.end(); d++) { for (d = p_profile->daylist.begin(); d != p_profile->daylist.end(); d++) {
@ -154,12 +154,10 @@ void SummaryChart::SetDay(Day * nullday)
} }
// for each day object on record for this date // for each day object on record for this date
int dlistsize = d.value().size(); day = d.value();
for (int i = 0; i < dlistsize; ++i) {
day = d.value().at(i);
// skip any empty or irrelevant day records // skip any empty or irrelevant day records
if (!day || (day->machine_type() != m_machinetype)) { continue; } if (!day || (day->machine(m_machinetype) == nullptr)) { continue; }
int ft = qint64(day->first()) / 1000L; int ft = qint64(day->first()) / 1000L;
ft += tz_offset; // convert to local time ft += tz_offset; // convert to local time
@ -212,7 +210,6 @@ void SummaryChart::SetDay(Day * nullday)
m_hours[dn] = total; m_hours[dn] = total;
m_empty = false; m_empty = false;
} }
}
} else { } else {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Data Channel summary charts // Data Channel summary charts
@ -225,14 +222,12 @@ void SummaryChart::SetDay(Day * nullday)
type = m_type[j]; type = m_type[j];
EventDataType typeval = m_typeval[j]; EventDataType typeval = m_typeval[j];
// for each machine object for this day day = d.value();
for (int i = 0; i < d.value().size(); i++) {
day = d.value()[i];
CPAPMode mode = (CPAPMode)(int)day->settings_max(CPAP_Mode); CPAPMode mode = (CPAPMode)(int)day->settings_max(CPAP_Mode);
// ignore irrelevent day objects // ignore irrelevent day objects
if (day->machine_type() != m_machinetype) { continue; } if (day->machine(m_machinetype) == nullptr) { continue; }
bool hascode = //day->channelHasData(code) || bool hascode = //day->channelHasData(code) ||
type == ST_HOURS || type == ST_HOURS ||
@ -293,7 +288,7 @@ void SummaryChart::SetDay(Day * nullday)
break; break;
case ST_CPH: case ST_CPH:
tmp = day->count(code) / day->hours(); tmp = day->count(code) / day->hours(m_machinetype);
break; break;
case ST_SPH: case ST_SPH:
@ -301,7 +296,7 @@ void SummaryChart::SetDay(Day * nullday)
break; break;
case ST_HOURS: case ST_HOURS:
tmp = day->hours(); tmp = day->hours(m_machinetype);
break; break;
case ST_SESSIONS: case ST_SESSIONS:
@ -348,16 +343,15 @@ void SummaryChart::SetDay(Day * nullday)
m_goodcodes[j] = true; m_goodcodes[j] = true;
fnd = true; fnd = true;
break;
}
} }
} }
if (fnd) { if (fnd) {
if (!m_fday) { m_fday = dn; } if (!m_fday) { m_fday = dn; }
m_values[dn][0] = total; m_values[dn][0] = total;
m_hours[dn] = day->hours(); m_hours[dn] = day->hours(m_machinetype);
if (m_graphtype == GT_BAR) { if (m_graphtype == GT_BAR) {
if (total < m_miny) { m_miny = total; } if (total < m_miny) { m_miny = total; }

View File

@ -34,7 +34,11 @@ void gDailySummary::SetDay(Day *day)
pie_total = 0; pie_total = 0;
m_day = day; m_day = day;
if (day) { Machine * cpap = nullptr;
if (day) cpap = day->machine(MT_CPAP);
if (cpap) {
m_minx = m_day->first(); m_minx = m_day->first();
m_maxx = m_day->last();; m_maxx = m_day->last();;
@ -103,8 +107,9 @@ void gDailySummary::SetDay(Day *day)
info.append(QObject::tr("%1: %2").arg(STR_TR_AHI).arg(day->calcAHI(),0,'f',2)); info.append(QObject::tr("%1: %2").arg(STR_TR_AHI).arg(day->calcAHI(),0,'f',2));
info_background.append(QColor("orange")); info_background.append(QColor("orange"));
settings.append(day->machine->brand()+ " " + day->machine->series());
settings.append(day->machine->model()+ " " + day->machine->modelnumber()); settings.append(cpap->brand()+ " " + cpap->series());
settings.append(cpap->model()+ " " + cpap->modelnumber());
settings.append(schema::channel[CPAP_Mode].option(mode)); settings.append(schema::channel[CPAP_Mode].option(mode));
if (mode == MODE_CPAP) { if (mode == MODE_CPAP) {

View File

@ -15,8 +15,7 @@
#include "day.h" #include "day.h"
#include "profiles.h" #include "profiles.h"
Day::Day(Machine *m) Day::Day()
: machine(m)
{ {
d_firstsession = true; d_firstsession = true;
} }
@ -26,10 +25,53 @@ Day::~Day()
delete(*s); delete(*s);
} }
} }
MachineType Day::machine_type() const
Session * Day::firstSession(MachineType type)
{ {
return machine->type(); for (int i=0; i<sessions.size(); i++) {
Session * sess = sessions.at(i);
if (!sess->enabled()) continue;
if (sess->machine()->type() == type) {
return sess;
} }
}
return nullptr;
}
bool Day::addMachine(Machine *mach)
{
if (!machines.contains(mach->type())) {
machines[mach->type()] = mach;
return true;
}
return false;
}
Machine *Day::machine(MachineType type)
{
QHash<MachineType,Machine *>::iterator it = machines.find(type);
if (it != machines.end())
return it.value();
return nullptr;
}
QList<Session *> Day::getSessions(MachineType type)
{
QList<Session *>::iterator it;
QList<Session *>::iterator sess_end = sessions.end();
QList<Session *> newlist;
for (it = sessions.begin(); it != sess_end; ++it) {
if (!(*it)->enabled())
continue;
if ((*it)->machine()->type() == type)
newlist.append((*it));
}
return newlist;
}
Session *Day::find(SessionID sessid) Session *Day::find(SessionID sessid)
{ {
QList<Session *>::iterator end=sessions.end(); QList<Session *>::iterator end=sessions.end();
@ -42,12 +84,19 @@ Session *Day::find(SessionID sessid)
return nullptr; return nullptr;
} }
void Day::AddSession(Session *s) void Day::addSession(Session *s)
{ {
if (!s) { Q_ASSERT(s!=nullptr);
qWarning("Day::AddSession called with nullptr session object"); QHash<MachineType, Machine *>::iterator mi = machines.find(s->machine()->type());
if (mi != machines.end()) {
if (mi.value() != s->machine()) {
qDebug() << "SleepyHead can't add session" << s->session() << "to this day record, as it already contains a different machine of the same MachineType";
return; return;
} }
} else {
machines[s->machine()->type()] = s->machine();
}
sessions.push_back(s); sessions.push_back(s);
} }
@ -489,7 +538,7 @@ qint64 Day::total_time()
for (QList<Session *>::iterator it = sessions.begin(); it != end; ++it) { for (QList<Session *>::iterator it = sessions.begin(); it != end; ++it) {
Session &sess = *(*it); Session &sess = *(*it);
if (sess.enabled()) { if (sess.enabled() && (sess.machine()->type() != MT_JOURNAL)) {
first = sess.first(); first = sess.first();
last = sess.last(); last = sess.last();
@ -536,6 +585,68 @@ qint64 Day::total_time()
return total; //d_totaltime; return total; //d_totaltime;
} }
// Total session time in milliseconds, only considering machinetype
qint64 Day::total_time(MachineType type)
{
qint64 d_totaltime = 0;
QMultiMap<qint64, bool> range;
//range.reserve(size()*2);
// Remember sessions may overlap..
qint64 first, last;
QList<Session *>::iterator end = sessions.end();
for (QList<Session *>::iterator it = sessions.begin(); it != end; ++it) {
Session &sess = *(*it);
if ((sess.machine()->type() == type) && sess.enabled()) {
first = sess.first();
last = sess.last();
// This algorithm relies on non zero length, and correctly ordered sessions
if (last > first) {
range.insert(first, 0);
range.insert(last, 1);
d_totaltime += sess.length();
}
}
}
bool b;
int nest = 0;
qint64 ti = 0;
qint64 total = 0;
// This is my implementation of a typical "brace counting" algorithm mentioned here:
// http://stackoverflow.com/questions/7468948/problem-calculating-overlapping-date-ranges
QMultiMap<qint64, bool>::iterator rend = range.end();
for (QMultiMap<qint64, bool>::iterator rit = range.begin(); rit != rend; ++rit) {
b = rit.value();
if (!b) {
if (!ti) {
ti = rit.key();
}
nest++;
} else {
if (--nest <= 0) {
total += rit.key() - ti;
ti = 0;
}
}
}
if (total != d_totaltime) {
// They can overlap.. tough.
// qDebug() << "Sessions Times overlaps!" << total << d_totaltime;
}
return total; //d_totaltime;
}
bool Day::hasEnabledSessions() bool Day::hasEnabledSessions()
{ {
QList<Session *>::iterator end = sessions.end(); QList<Session *>::iterator end = sessions.end();
@ -549,6 +660,19 @@ bool Day::hasEnabledSessions()
return false; return false;
} }
bool Day::hasEnabledSessions(MachineType type)
{
QList<Session *>::iterator end = sessions.end();
for (QList<Session *>::iterator it = sessions.begin(); it != end; ++it) {
if (((*it)->machine()->type() == type) && (*it)->enabled()) {
return true;
}
}
return false;
}
/*EventDataType Day::percentile(ChannelID code,double percent) /*EventDataType Day::percentile(ChannelID code,double percent)
{ {
double val=0; double val=0;
@ -946,7 +1070,12 @@ void Day::CloseEvents()
QList<ChannelID> Day::getSortedMachineChannels(quint32 chantype) QList<ChannelID> Day::getSortedMachineChannels(quint32 chantype)
{ {
QList<ChannelID> available = machine->availableChannels(chantype); QList<ChannelID> available;
QHash<MachineType, Machine *>::iterator mi_end = machines.end();
for (QHash<MachineType, Machine *>::iterator mi = machines.begin(); mi != mi_end; mi++) {
if (mi.key() == MT_JOURNAL) continue;
available.append(mi.value()->availableChannels(chantype));
}
QMultiMap<int, ChannelID> order; QMultiMap<int, ChannelID> order;
@ -965,6 +1094,31 @@ QList<ChannelID> Day::getSortedMachineChannels(quint32 chantype)
return channels; return channels;
} }
qint64 Day::first(MachineType type)
{
qint64 date = 0;
qint64 tmp;
QList<Session *>::iterator end = sessions.end();
for (QList<Session *>::iterator it = sessions.begin(); it != end; ++it) {
Session & sess = *(*it);
if ((sess.machine()->type() == type) && sess.enabled()) {
tmp = sess.first();
if (!tmp) { continue; }
if (!date) {
date = tmp;
} else {
if (tmp < date) { date = tmp; }
}
}
}
return date;
}
qint64 Day::first() qint64 Day::first()
{ {
qint64 date = 0; qint64 date = 0;
@ -1017,6 +1171,33 @@ qint64 Day::last()
return date; return date;
} }
qint64 Day::last(MachineType type)
{
qint64 date = 0;
qint64 tmp;
QList<Session *>::iterator end = sessions.end();
for (QList<Session *>::iterator it = sessions.begin(); it != end; ++it) {
Session & sess = *(*it);
if ((sess.machine()->type() == type) && sess.enabled()) {
tmp = sess.last();
if (!tmp) { continue; }
if (!date) {
date = tmp;
} else {
if (tmp > date) { date = tmp; }
}
}
}
return date;
}
bool Day::removeSession(Session *sess) bool Day::removeSession(Session *sess)
{ {
return sessions.removeAll(sess) > 0; return sessions.removeAll(sess) > 0;
@ -1024,7 +1205,7 @@ bool Day::removeSession(Session *sess)
QString Day::getCPAPMode() QString Day::getCPAPMode()
{ {
Q_ASSERT(machine_type() == MT_CPAP); Q_ASSERT(machine(MT_CPAP) != nullptr);
CPAPMode mode = (CPAPMode)(int)qRound(settings_wavg(CPAP_Mode)); CPAPMode mode = (CPAPMode)(int)qRound(settings_wavg(CPAP_Mode));
if (mode == MODE_CPAP) { if (mode == MODE_CPAP) {
@ -1047,7 +1228,10 @@ QString Day::getCPAPMode()
QString Day::getPressureRelief() QString Day::getPressureRelief()
{ {
CPAPLoader * loader = qobject_cast<CPAPLoader *>(machine->loader()); Machine * mach = machine(MT_CPAP);
if (!mach) return STR_MessageBox_Error;
CPAPLoader * loader = qobject_cast<CPAPLoader *>(mach->loader());
if (!loader) return STR_MessageBox_Error; if (!loader) return STR_MessageBox_Error;
@ -1072,7 +1256,7 @@ QString Day::getPressureRelief()
QString Day::getPressureSettings() QString Day::getPressureSettings()
{ {
Q_ASSERT(machine_type() == MT_CPAP); Q_ASSERT(machine(MT_CPAP) != nullptr);
CPAPMode mode = (CPAPMode)(int)settings_max(CPAP_Mode); CPAPMode mode = (CPAPMode)(int)settings_max(CPAP_Mode);
QString units = schema::channel[CPAP_Pressure].units(); QString units = schema::channel[CPAP_Pressure].units();

View File

@ -31,14 +31,20 @@ class Session;
class Day class Day
{ {
public: public:
Day(Machine *m); Day();
~Day(); ~Day();
//! \brief Add Session to this Day object (called during Load) //! \brief Add a new machine to this day record
void AddSession(Session *s); bool addMachine(Machine *m);
//! \brief Returns this machines type //! \brief Returns a machine record if present of specified machine type
MachineType machine_type() const; Machine *machine(MachineType type);
//! \brief Returns a list of sessions for the specified machine type
QList<Session *> getSessions(MachineType type);
//! \brief Add Session to this Day object (called during Load)
void addSession(Session *s);
//! \brief Returns the count of all this days sessions' events for this day //! \brief Returns the count of all this days sessions' events for this day
EventDataType count(ChannelID code); EventDataType count(ChannelID code);
@ -113,6 +119,13 @@ class Day
//! \brief Returns the last session time of this day //! \brief Returns the last session time of this day
qint64 last(); qint64 last();
//! \brief Returns the first session time of this machine type for this day
qint64 first(MachineType type);
//! \brief Returns the last session time of this machine type for this day
qint64 last(MachineType type);
// //! \brief Sets the first session time of this day // //! \brief Sets the first session time of this day
// void setFirst(qint64 val) { d_first=val; } // void setFirst(qint64 val) { d_first=val; }
@ -128,11 +141,18 @@ class Day
//! \brief Returns the total time in milliseconds for this day //! \brief Returns the total time in milliseconds for this day
qint64 total_time(); qint64 total_time();
//! \brief Returns the total time in milliseconds for this day for given machine type
qint64 total_time(MachineType type);
//! \brief Returns true if this day has enabled sessions for supplied machine type
bool hasEnabledSessions(MachineType);
//! \brief Returns true if this day has enabled sessions //! \brief Returns true if this day has enabled sessions
bool hasEnabledSessions(); bool hasEnabledSessions();
//! \brief Return the total time in decimal hours for this day //! \brief Return the total time in decimal hours for this day
EventDataType hours() { return double(total_time()) / 3600000.0; } EventDataType hours() { return double(total_time()) / 3600000.0; }
EventDataType hours(MachineType type) { return double(total_time(type)) / 3600000.0; }
//! \brief Return the session indexed by i //! \brief Return the session indexed by i
Session *operator [](int i) { return sessions[i]; } Session *operator [](int i) { return sessions[i]; }
@ -153,8 +173,6 @@ class Day
//! \brief Returns the number of Sessions in this day record //! \brief Returns the number of Sessions in this day record
int size() { return sessions.size(); } int size() { return sessions.size(); }
Machine *machine;
//! \brief Loads all Events files for this Days Sessions //! \brief Loads all Events files for this Days Sessions
void OpenEvents(); void OpenEvents();
@ -239,8 +257,13 @@ class Day
EventDataType calc(ChannelID code, ChannelCalcType type); EventDataType calc(ChannelID code, ChannelCalcType type);
Session * firstSession(MachineType type);
//! \brief A QList containing all Sessions objects for this day
QList<Session *> sessions; QList<Session *> sessions;
QHash<MachineType, Machine *> machines;
protected: protected:
//! \brief A Vector containing all sessions for this day //! \brief A Vector containing all sessions for this day
QHash<ChannelID, QHash<EventDataType, EventDataType> > perc_cache; QHash<ChannelID, QHash<EventDataType, EventDataType> > perc_cache;

View File

@ -64,7 +64,7 @@ JournalEntry::JournalEntry(QDate date)
session = nullptr; session = nullptr;
day = p_profile->GetDay(date, MT_JOURNAL); day = p_profile->GetDay(date, MT_JOURNAL);
if (!day) { if (!day) {
session = day->sessions[0]; session = day->firstSession(MT_JOURNAL);
} else { } else {
// Doesn't exist.. create a new one.. // Doesn't exist.. create a new one..
session = new Session(jmach,0); session = new Session(jmach,0);
@ -227,7 +227,7 @@ void BackupJournal(QString filename)
Day * journal = p_profile->GetDay(date, MT_JOURNAL); Day * journal = p_profile->GetDay(date, MT_JOURNAL);
if (!journal) continue; if (!journal) continue;
Session * sess = journal->sessions[0]; Session * sess = journal->firstSession(MT_JOURNAL);
if (!sess) continue; if (!sess) continue;
QDomElement day = doc.createElement("day"); QDomElement day = doc.createElement("day");
day.setAttribute("date", date.toString()); day.setAttribute("date", date.toString());

View File

@ -59,10 +59,6 @@ Machine::Machine(MachineID id)
Machine::~Machine() Machine::~Machine()
{ {
qDebug() << "Destroy Machine" << info.loadername << hex << m_id; qDebug() << "Destroy Machine" << info.loadername << hex << m_id;
for (QMap<QDate, Day *>::iterator d = day.begin(); d != day.end(); d++) {
delete d.value();
}
} }
Session *Machine::SessionExists(SessionID session) Session *Machine::SessionExists(SessionID session)
{ {
@ -208,17 +204,11 @@ bool Machine::AddSession(Session *s)
dit = day.find(date); dit = day.find(date);
if (dit == day.end()) { if (dit == day.end()) {
//QString dstr=date.toString("yyyyMMdd"); dit = day.insert(date, p_profile->addDay(date));
//qDebug("Adding Profile Day %s",dstr.toLatin1().data());
dd = new Day(this);
day[date] = dd;
// Add this Day record to profile
p_profile->AddDay(date, dd, m_type);
} else {
dd = *dit;
} }
dd = dit.value();
dd->AddSession(s); dd->addSession(s);
if (combine_next_day) { if (combine_next_day) {
for (QList<Session *>::iterator i = nextday.value()->begin(); i != nextday.value()->end(); i++) { for (QList<Session *>::iterator i = nextday.value()->begin(); i != nextday.value()->end(); i++) {
@ -229,7 +219,7 @@ bool Machine::AddSession(Session *s)
sessionlist[(*i)->session()] = *i; sessionlist[(*i)->session()] = *i;
dd->AddSession(*i); dd->addSession(*i);
} }
// QMap<QDate, QList<Day *> >::iterator nd = p_profile->daylist.find(date.addDays(1)); // QMap<QDate, QList<Day *> >::iterator nd = p_profile->daylist.find(date.addDays(1));
@ -692,7 +682,6 @@ QList<ChannelID> Machine::availableChannels(quint32 chantype)
{ {
QHash<ChannelID, int> chanhash; QHash<ChannelID, int> chanhash;
// look through the daylist and return a list of available channels for this machine // look through the daylist and return a list of available channels for this machine
QMap<QDate, Day *>::iterator dit; QMap<QDate, Day *>::iterator dit;
QMap<QDate, Day *>::iterator day_end = day.end(); QMap<QDate, Day *>::iterator day_end = day.end();
@ -701,6 +690,8 @@ QList<ChannelID> Machine::availableChannels(quint32 chantype)
for (QList<Session *>::iterator sit = dit.value()->begin(); sit != sess_end; ++sit) { for (QList<Session *>::iterator sit = dit.value()->begin(); sit != sess_end; ++sit) {
Session * sess = (*sit); Session * sess = (*sit);
if (sess->machine() != this) continue;
int size = sess->availableChannels().size(); int size = sess->availableChannels().size();
for (int i=0; i < size; ++i) { for (int i=0; i < size; ++i) {
ChannelID code = sess->availableChannels().at(i); ChannelID code = sess->availableChannels().at(i);

View File

@ -103,6 +103,7 @@ Machine * MachineLoader::CreateMachine(MachineInfo info, MachineID id)
break; break;
case MT_JOURNAL: case MT_JOURNAL:
m = new Machine(id); m = new Machine(id);
m->setType(MT_JOURNAL);
break; break;
default: default:
m = new Machine(id); m = new Machine(id);
@ -246,7 +247,7 @@ void MachineLoader::runTasks(bool threaded)
QList<ChannelID> CPAPLoader::eventFlags(Day * day) QList<ChannelID> CPAPLoader::eventFlags(Day * day)
{ {
Machine * mach = day->machine; Machine * mach = day->machine(MT_CPAP);
QList<ChannelID> list; QList<ChannelID> list;

View File

@ -84,6 +84,11 @@ Profile::~Profile()
} }
m_opened=false; m_opened=false;
} }
for (QMap<QDate, Day *>::iterator d = daylist.begin(); d != daylist.end(); d++) {
delete d.value();
}
} }
bool Profile::Save(QString filename) bool Profile::Save(QString filename)
@ -572,16 +577,16 @@ QDomElement Profile::ExtraSave(QDomDocument &doc)
} }
return mach; return mach;
} }
void Profile::AddDay(QDate date, Day *day, MachineType mt)
Day *Profile::addDay(QDate date)
{ {
//date+=wxTimeSpan::Day(); QMap<QDate, Day *>::iterator dit = daylist.find(date);
if (!day) { if (dit == daylist.end()) {
qDebug() << "Profile::AddDay called with null day object"; dit = daylist.insert(date, new Day());
return;
} }
Day * day = dit.value();
if (is_first_day) { if (is_first_day) {
m_first = m_last = date; m_first = m_last = date;
@ -595,23 +600,7 @@ void Profile::AddDay(QDate date, Day *day, MachineType mt)
if (m_last < date) { if (m_last < date) {
m_last = date; m_last = date;
} }
return day;
// Check for any other machines of same type.. Throw an exception if one already exists.
QList<Day *> &dl = daylist[date];
for (QList<Day *>::iterator a = dl.begin(); a != dl.end(); a++) {
if ((*a)->machine->type() == mt) {
// disabled this because two machines isn't all that bad
// if (QMessageBox::question(nullptr,"Different Machine Detected","This data comes from another machine to what's usually imported, and has overlapping data.\nThis new data will override any older data from the old machine. Are you sure you want to do this?",QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) {
// throw OneTypePerDay();
// }
daylist[date].erase(a);
break;
}
}
daylist[date].push_back(day);
} }
// Get Day record if data available for date and machine type, // Get Day record if data available for date and machine type,
@ -622,14 +611,10 @@ Day *Profile::GetGoodDay(QDate date, MachineType type)
if (!day) if (!day)
return nullptr; return nullptr;
// Just return the day if not matching for a machine.
if (type == MT_UNKNOWN)
return day;
// For a machine match, find at least one enabled Session. // For a machine match, find at least one enabled Session.
Q_ASSERT(day->machine_type() == type);
for (int i = 0; i < day->size(); ++i) { for (int i = 0; i < day->size(); ++i) {
if ((*day)[i]->enabled()) Session * sess = (*day)[i];
if (((type == MT_UNKNOWN) || (sess->machine()->type() == type)) && sess->enabled())
return day; return day;
} }
@ -639,24 +624,14 @@ Day *Profile::GetGoodDay(QDate date, MachineType type)
Day *Profile::GetDay(QDate date, MachineType type) Day *Profile::GetDay(QDate date, MachineType type)
{ {
if (!daylist.contains(date)) QMap<QDate, Day *>::iterator di = daylist.find(date);
return nullptr; if (di == daylist.end()) return nullptr;
QList<Day *> list(daylist.value(date)); Day * day = di.value();
QList<Day *>::iterator it = list.begin(); if (type == MT_UNKNOWN) return day; // just want the day record
QList<Day *>::iterator list_end = list.end();
for (; it != list_end; ++it) { if (day->machines.contains(type)) return day;
Day * day = (*it);
Q_ASSERT(day != nullptr);
// Just return the day if not matching for a machine.
if (day->machine_type() == type || type == MT_UNKNOWN) {
return day;
}
}
return nullptr; return nullptr;
} }
@ -765,33 +740,17 @@ Machine *Profile::GetMachine(MachineType t)
bool Profile::unlinkDay(Day * day) bool Profile::unlinkDay(Day * day)
{ {
bool b=false; QMap<QDate, Day *>::iterator it;
QMap<QDate, Day *>::iterator it_end = daylist.end();
QList<QDate> dates;
QMap<QDate, QList<Day *> >::iterator it;
QMap<QDate, QList<Day *> >::iterator it_end = daylist.end();
// Find the key...
for (it = daylist.begin(); it != it_end; ++it) { for (it = daylist.begin(); it != it_end; ++it) {
if (it.value().contains(day)) { if (it.value() == day) {
dates.push_back(it.key());
}
}
for (int i=0; i < dates.size(); ++i) {
it = daylist.find(dates.at(i));
if (it != daylist.end()) {
it.value().removeAll(day);
// TODO: Check it doesn't change from the above...
if (it.value().size() == 0) {
daylist.erase(it); daylist.erase(it);
return true;
} }
} }
} return false;
return b;
} }
@ -847,6 +806,7 @@ Profile *Create(QString name)
p_profile->Set(STR_GEN_DataFolder, QString("{home}/Profiles/{") + QString(STR_UI_UserName) + QString("}")); p_profile->Set(STR_GEN_DataFolder, QString("{home}/Profiles/{") + QString(STR_UI_UserName) + QString("}"));
Machine *m = new Machine(0); Machine *m = new Machine(0);
m->setType(MT_JOURNAL);
MachineInfo info(MT_JOURNAL, 0, STR_MACH_Journal, "SleepyHead", STR_MACH_Journal, QString(), m->hexid(), QString(), QDateTime::currentDateTime(), 0); MachineInfo info(MT_JOURNAL, 0, STR_MACH_Journal, "SleepyHead", STR_MACH_Journal, QString(), m->hexid(), QString(), QDateTime::currentDateTime(), 0);
m->setInfo(info); m->setInfo(info);
@ -906,35 +866,42 @@ void Scan()
// Returns a list of all days records matching machine type between start and end date // Returns a list of all days records matching machine type between start and end date
QList<Day *> Profile::getDays(MachineType mt, QDate start, QDate end) QList<Day *> Profile::getDays(MachineType mt, QDate start, QDate end)
{ {
QList<Day *> daylist; QList<Day *> list;
if (!start.isValid()) { if (!start.isValid()) {
return daylist; return list;
} }
if (!end.isValid()) { if (!end.isValid()) {
return daylist; return list;
} }
QDate date = start; QDate date = start;
if (date.isNull()) { if (date.isNull()) {
return daylist; return list;
} }
QMap<QDate, Day *>::iterator it;
do { do {
Day *day = GetGoodDay(date, mt); it = daylist.find(date);
if (it != daylist.end()) {
if (day) { Day *day = it.value();
if ((mt == MT_UNKNOWN) || (day->machine->type() == mt)) { if (mt != MT_UNKNOWN) {
daylist.push_back(day); if (day->hasEnabledSessions(mt)) {
list.push_back(day);
}
} else {
if (day->hasEnabledSessions()) {
list.push_back(day);
}
} }
} }
date = date.addDays(1); date = date.addDays(1);
} while (date <= end); } while (date <= end);
return daylist; return list;
} }
int Profile::countDays(MachineType mt, QDate start, QDate end) int Profile::countDays(MachineType mt, QDate start, QDate end)
@ -959,7 +926,7 @@ int Profile::countDays(MachineType mt, QDate start, QDate end)
Day *day = GetGoodDay(date, mt); Day *day = GetGoodDay(date, mt);
if (day) { if (day) {
if ((mt == MT_UNKNOWN) || (day->machine->type() == mt)) { days++; } days++;
} }
date = date.addDays(1); date = date.addDays(1);
@ -993,7 +960,7 @@ int Profile::countCompliantDays(MachineType mt, QDate start, QDate end)
Day *day = GetGoodDay(date, mt); Day *day = GetGoodDay(date, mt);
if (day) { if (day) {
if ((day->machine->type() == mt) && (day->hours() > compliance)) { days++; } if (day->hours(mt) > compliance) { days++; }
} }
date = date.addDays(1); date = date.addDays(1);
@ -1671,9 +1638,7 @@ bool Profile::hasChannel(ChannelID code)
return false; return false;
} }
QMap<QDate, QList<Day *> >::iterator dit; QMap<QDate, Day *>::iterator dit;
QList<Day *>::iterator di;
QList<Day *>::iterator di_end;
bool found = false; bool found = false;
@ -1681,22 +1646,13 @@ bool Profile::hasChannel(ChannelID code)
dit = daylist.find(d); dit = daylist.find(d);
if (dit != daylist.end()) { if (dit != daylist.end()) {
Day *day = dit.value();
di = dit.value().begin();
di_end = dit.value().end();
for (; di != di_end; ++di) {
Day *day = (*di);
if (day->channelHasData(code)) { if (day->channelHasData(code)) {
found = true; found = true;
break; break;
} }
} }
}
if (found) {
break;
}
d = d.addDays(-1); d = d.addDays(-1);
} while (d >= f); } while (d >= f);

View File

@ -82,7 +82,7 @@ class Profile : public Preferences
// bool trashMachine(Machine * mach); // bool trashMachine(Machine * mach);
//! \brief Add Day record to Profile Day list //! \brief Add Day record to Profile Day list
void AddDay(QDate date, Day *day, MachineType mt); Day *addDay(QDate date);
//! \brief Get Day record if data available for date and machine type, else return nullptr //! \brief Get Day record if data available for date and machine type, else return nullptr
Day *GetDay(QDate date, MachineType type = MT_UNKNOWN); Day *GetDay(QDate date, MachineType type = MT_UNKNOWN);
@ -186,8 +186,8 @@ class Profile : public Preferences
//! \brief Return if this profile has been opened or not //! \brief Return if this profile has been opened or not
bool isOpen() { return m_opened; } bool isOpen() { return m_opened; }
//! \brief Red-Black tree of Days (iterates in order). //! \brief QMap of day records (iterates in order).
QMap<QDate, QList<Day *> > daylist; QMap<QDate, Day *> daylist;
//! \brief List of machines, indexed by MachineID. //! \brief List of machines, indexed by MachineID.
QHash<MachineID, Machine *> machlist; QHash<MachineID, Machine *> machlist;

View File

@ -168,7 +168,9 @@ bool Session::Store(QString path)
bool Session::StoreSummary(QString filename) bool Session::StoreSummary(QString filename)
{ {
if (filename.isEmpty()) {
filename = machine()->getDataPath() + QString().sprintf("%08lx.000", s_session);
}
QFile file(filename); QFile file(filename);
file.open(QIODevice::WriteOnly); file.open(QIODevice::WriteOnly);
@ -476,6 +478,10 @@ const quint16 compress_method = 1;
bool Session::StoreEvents(QString filename) bool Session::StoreEvents(QString filename)
{ {
if (filename.isEmpty()) {
filename = machine()->getDataPath() + QString().sprintf("%08lx.001", s_session);
}
QFile file(filename); QFile file(filename);
file.open(QIODevice::WriteOnly); file.open(QIODevice::WriteOnly);

View File

@ -40,10 +40,10 @@ class Session
bool Store(QString path); bool Store(QString path);
//! \brief Writes the Sessions Summary Indexes to filename, in SleepLibs custom data format. //! \brief Writes the Sessions Summary Indexes to filename, in SleepLibs custom data format.
bool StoreSummary(QString filename); bool StoreSummary(QString filename = QString());
//! \brief Writes the Sessions EventLists to filename, in SleepLibs custom data format. //! \brief Writes the Sessions EventLists to filename, in SleepLibs custom data format.
bool StoreEvents(QString filename); bool StoreEvents(QString filename = QString());
//bool Load(QString path); //bool Load(QString path);

View File

@ -126,7 +126,7 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
GraphView=new gGraphView(ui->graphFrame,shared); GraphView=new gGraphView(ui->graphFrame,shared);
GraphView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); GraphView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
snapGV=new gGraphView(GraphView); //ui->graphMainArea); snapGV=new gGraphView(GraphView);
snapGV->setMinimumSize(172,172); snapGV->setMinimumSize(172,172);
snapGV->hideSplitter(); snapGV->hideSplitter();
snapGV->hide(); snapGV->hide();
@ -520,15 +520,10 @@ void Daily::closeEvent(QCloseEvent *event)
void Daily::doToggleSession(Session * sess) void Daily::doToggleSession(Session * sess)
{ {
Q_UNUSED(sess)
sess->setEnabled(!sess->enabled()); sess->setEnabled(!sess->enabled());
sess->StoreSummary();
// sess->StoreSummary(); LoadDate(previous_date);
Day *day=p_profile->GetDay(previous_date,MT_CPAP);
if (day) {
day->machine->Save();
this->LoadDate(previous_date);
}
} }
void Daily::Link_clicked(const QUrl &url) void Daily::Link_clicked(const QUrl &url)
@ -537,21 +532,20 @@ void Daily::Link_clicked(const QUrl &url)
QString data=url.toString().section("=",1); QString data=url.toString().section("=",1);
int sid=data.toInt(); int sid=data.toInt();
Day *day=nullptr; Day *day=nullptr;
if (code=="togglecpapsession") { // Enable/Disable CPAP session if (code=="togglecpapsession") { // Enable/Disable CPAP session
day=p_profile->GetDay(previous_date,MT_CPAP); day=p_profile->GetDay(previous_date,MT_CPAP);
if (!day) return;
Session *sess=day->find(sid); Session *sess=day->find(sid);
if (!sess) if (!sess)
return; return;
int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical); int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
sess->setEnabled(!sess->enabled()); sess->setEnabled(!sess->enabled());
sess->StoreSummary();
// Messy, this rewrites both summary & events.. TODO: Write just the session summary file
day->machine->Save();
// Reload day // Reload day
this->LoadDate(previous_date); LoadDate(previous_date);
webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i); webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
return;
} else if (code=="toggleoxisession") { // Enable/Disable Oximetry session } else if (code=="toggleoxisession") { // Enable/Disable Oximetry session
day=p_profile->GetDay(previous_date,MT_OXIMETER); day=p_profile->GetDay(previous_date,MT_OXIMETER);
Session *sess=day->find(sid); Session *sess=day->find(sid);
@ -559,19 +553,29 @@ void Daily::Link_clicked(const QUrl &url)
return; return;
int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical); int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
sess->setEnabled(!sess->enabled()); sess->setEnabled(!sess->enabled());
// Messy, this rewrites both summary & events.. TODO: Write just the session summary file
day->machine->Save(); sess->StoreSummary();
// Reload day // Reload day
this->LoadDate(previous_date); LoadDate(previous_date);
webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i); webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
return;
} else if (code=="cpap") { } else if (code=="cpap") {
day=p_profile->GetDay(previous_date,MT_CPAP); day=p_profile->GetDay(previous_date,MT_CPAP);
if (day) {
Session *sess=day->machine(MT_CPAP)->sessionlist[sid];
if (sess && sess->enabled()) {
GraphView->SetXBounds(sess->first(),sess->last());
}
}
} else if (code=="oxi") { } else if (code=="oxi") {
//day=p_profile->GetDay(previous_date,MT_OXIMETER); day=p_profile->GetDay(previous_date,MT_OXIMETER);
//Session *sess=day->machine->sessionlist[sid]; if (day) {
return; Session *sess=day->machine(MT_OXIMETER)->sessionlist[sid];
if (sess && sess->enabled()) {
GraphView->SetXBounds(sess->first(),sess->last());
}
}
} else if (code=="event") { } else if (code=="event") {
QList<QTreeWidgetItem *> list=ui->treeWidget->findItems(schema::channel[sid].fullname(),Qt::MatchContains); QList<QTreeWidgetItem *> list=ui->treeWidget->findItems(schema::channel[sid].fullname(),Qt::MatchContains);
if (list.size()>0) { if (list.size()>0) {
@ -588,13 +592,6 @@ void Daily::Link_clicked(const QUrl &url)
} else { } else {
qDebug() << "Clicked on" << code << data; qDebug() << "Clicked on" << code << data;
} }
if (day) {
Session *sess=day->machine->sessionlist[sid];
if (sess && sess->enabled()) {
GraphView->SetXBounds(sess->first(),sess->last());
}
}
} }
void Daily::ReloadGraphs() void Daily::ReloadGraphs()
@ -916,24 +913,19 @@ MyWebView::MyWebView(QWidget *parent):
} }
QString Daily::getSessionInformation(Day * cpap, Day * oxi, Day * stage, Day * posit) QString Daily::getSessionInformation(Day * day)
{ {
QString html; QString html;
QList<Day *> list; if (!day) return html;
if (cpap) list.push_back(cpap);
if (oxi) list.push_back(oxi);
if (stage) list.push_back(stage);
if (posit) list.push_back(posit);
if (list.isEmpty())
return html;
html="<table cellpadding=0 cellspacing=0 border=0 width=100%>"; html="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
html+=QString("<tr><td colspan=5 align=center><b>"+tr("Session Information")+"</b></td></tr>"); html+=QString("<tr><td colspan=5 align=center><b>"+tr("Session Information")+"</b></td></tr>");
html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>"; html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
QFontMetrics FM(*defaultfont); QFontMetrics FM(*defaultfont);
QRect r=FM.boundingRect('@'); QRect r=FM.boundingRect('@');
Machine * cpap = day->machine(MT_CPAP);
if (cpap) { if (cpap) {
html+=QString("<tr><td colspan=5 align=center>" html+=QString("<tr><td colspan=5 align=center>"
"<object type=\"application/x-qt-plugin\" classid=\"SessionBar\" name=\"sessbar\" height=%1 width=100%></object>" "<object type=\"application/x-qt-plugin\" classid=\"SessionBar\" name=\"sessbar\" height=%1 width=100%></object>"
@ -949,13 +941,15 @@ QString Daily::getSessionInformation(Day * cpap, Day * oxi, Day * stage, Day * p
bool corrupted_waveform=false; bool corrupted_waveform=false;
QString tooltip; QString tooltip;
QList<Day *>::iterator di;
QString type; QString type;
for (di=list.begin();di!=list.end();di++) { QHash<MachineType, Machine *>::iterator mach_end = day->machines.end();
Day * day=*di; QHash<MachineType, Machine *>::iterator mi;
for (mi = day->machines.begin(); mi != mach_end; ++mi) {
if (mi.key() == MT_JOURNAL) continue;
html += "<tr><td colspan=5 align=center><i>"; html += "<tr><td colspan=5 align=center><i>";
switch (day->machine_type()) { switch (mi.key()) {
case MT_CPAP: type="cpap"; case MT_CPAP: type="cpap";
html+=tr("CPAP Sessions"); html+=tr("CPAP Sessions");
break; break;
@ -981,9 +975,11 @@ QString Daily::getSessionInformation(Day * cpap, Day * oxi, Day * stage, Day * p
"<th>"+STR_TR_Start+"</th>" "<th>"+STR_TR_Start+"</th>"
"<th>"+STR_TR_End+"</th>" "<th>"+STR_TR_End+"</th>"
"<th>"+tr("Duration")+"</th></tr>"); "<th>"+tr("Duration")+"</th></tr>");
for (QList<Session *>::iterator s=day->begin();s!=day->end();++s) {
if ((day->machine_type()==MT_CPAP) && QList<Session *> sesslist = day->getSessions(mi.key());
for (QList<Session *>::iterator s=sesslist.begin(); s != sesslist.end(); ++s) {
if (((*s)->machine()->type() == MT_CPAP) &&
((*s)->settings.find(CPAP_BrokenWaveform) != (*s)->settings.end())) ((*s)->settings.find(CPAP_BrokenWaveform) != (*s)->settings.end()))
corrupted_waveform=true; corrupted_waveform=true;
@ -993,13 +989,6 @@ QString Daily::getSessionInformation(Day * cpap, Day * oxi, Day * stage, Day * p
int h=len/3600; int h=len/3600;
int m=(len/60) % 60; int m=(len/60) % 60;
int s1=len % 60; int s1=len % 60;
//tooltip=day->machine->loaderName()+QString(":#%1").arg((*s)->session(),8,10,QChar('0'));
//#define DEBUG_SESSIONS
//#ifdef DEBUG_SESSIONS
// tooltip += " "+QString::number(len)+"s";
//#endif
// tooltip needs to lookup language.. :-/
Session *sess=*s; Session *sess=*s;
if (!sess->settings.contains(SESSION_ENABLED)) { if (!sess->settings.contains(SESSION_ENABLED)) {
@ -1034,23 +1023,32 @@ QString Daily::getSessionInformation(Day * cpap, Day * oxi, Day * stage, Day * p
return html; return html;
} }
QString Daily::getMachineSettings(Day * cpap) { QString Daily::getMachineSettings(Day * day) {
QString html; QString html;
if (cpap && cpap->hasEnabledSessions()) {
Machine * cpap = day->machine(MT_CPAP);
if (cpap && day->hasEnabledSessions(MT_CPAP)) {
html="<table cellpadding=0 cellspacing=0 border=0 width=100%>"; html="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>").arg(tr("Machine Settings")); html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>").arg(tr("Machine Settings"));
html+="<tr><td colspan=5>&nbsp;</td></tr>"; html+="<tr><td colspan=5>&nbsp;</td></tr>";
if ((cpap && cpap->settingExists(CPAP_BrokenSummary))) { if ((day->settingExists(CPAP_BrokenSummary))) {
html+="<tr><td colspan=5 align=center><i>"+tr("Machine Settings Unavailable")+"</i></td></tr></table><hr/>\n"; html+="<tr><td colspan=5 align=center><i>"+tr("Machine Settings Unavailable")+"</i></td></tr></table><hr/>\n";
return html; return html;
} }
QMap<QString, QString> other; QMap<QString, QString> other;
QHash<ChannelID, QVariant>::iterator it = cpap->sessions.at(0)->settings.begin(); Session * sess = day->firstSession(MT_CPAP);
QHash<ChannelID, QVariant>::iterator it_end = cpap->sessions.at(0)->settings.end();
QHash<ChannelID, QVariant>::iterator it;
QHash<ChannelID, QVariant>::iterator it_end;
if (sess) {
it_end = sess->settings.end();
it = sess->settings.begin();
}
QMap<int, QString> first; QMap<int, QString> first;
for (; it != it_end; ++it) {
if (sess) for (; it != it_end; ++it) {
ChannelID code = it.key(); ChannelID code = it.key();
if ((code <= 1) || (code == RMS9_MaskOnTime)) continue; if ((code <= 1) || (code == RMS9_MaskOnTime)) continue;
@ -1137,31 +1135,36 @@ QString Daily::getMachineSettings(Day * cpap) {
return html; return html;
} }
QString Daily::getOximeterInformation(Day * oxi) QString Daily::getOximeterInformation(Day * day)
{ {
QString html; QString html;
if (oxi && oxi->hasEnabledSessions()) { Machine * oxi = day->machine(MT_OXIMETER);
if (oxi && day->hasEnabledSessions(MT_OXIMETER)) {
html="<table cellpadding=0 cellspacing=0 border=0 width=100%>"; html="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Oximeter Information")); html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Oximeter Information"));
html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>"; html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
html+="<tr><td colspan=5 align=center>"+oxi->machine->brand()+" "+oxi->machine->series()+"</td></tr>\n"; html+="<tr><td colspan=5 align=center>"+oxi->brand()+" "+oxi->series()+"</td></tr>\n";
html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>"; html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3%)</td></tr>").arg(tr("SpO2 Desaturations")).arg(oxi->count(OXI_SPO2Drop)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_SPO2Drop)/3600.0),0,'f',2); html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3%)</td></tr>").arg(tr("SpO2 Desaturations")).arg(day->count(OXI_SPO2Drop)).arg((100.0/day->hours(MT_OXIMETER)) * (day->sum(OXI_SPO2Drop)/3600.0),0,'f',2);
html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3%)</td></tr>").arg(tr("Pulse Change events")).arg(oxi->count(OXI_PulseChange)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_PulseChange)/3600.0),0,'f',2); html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3%)</td></tr>").arg(tr("Pulse Change events")).arg(day->count(OXI_PulseChange)).arg((100.0/day->hours(MT_OXIMETER)) * (day->sum(OXI_PulseChange)/3600.0),0,'f',2);
html+=QString("<tr><td colspan=5 align=center>%1: %2%</td></tr>").arg(tr("SpO2 Baseline Used")).arg(oxi->settings_wavg(OXI_SPO2Drop),0,'f',2); // CHECKME: Should this value be wavg OXI_SPO2 isntead? html+=QString("<tr><td colspan=5 align=center>%1: %2%</td></tr>").arg(tr("SpO2 Baseline Used")).arg(day->settings_wavg(OXI_SPO2Drop),0,'f',2); // CHECKME: Should this value be wavg OXI_SPO2 isntead?
html+="</table>\n"; html+="</table>\n";
html+="<hr/>\n"; html+="<hr/>\n";
} }
return html; return html;
} }
QString Daily::getCPAPInformation(Day * cpap) QString Daily::getCPAPInformation(Day * day)
{ {
QString html; QString html;
if (!cpap) if (!day)
return html; return html;
MachineInfo info = cpap->machine->getInfo(); Machine * cpap = day->machine(MT_CPAP);
if (!cpap) return html;
MachineInfo info = cpap->getInfo();
html="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"; html="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
@ -1174,10 +1177,10 @@ QString Daily::getCPAPInformation(Day * cpap)
//CPAPMode mode=(CPAPMode)(int)cpap->settings_max(CPAP_Mode); //CPAPMode mode=(CPAPMode)(int)cpap->settings_max(CPAP_Mode);
html+="<tr><td align=center>"; html+="<tr><td align=center>";
html+=tr("PAP Mode: %1<br/>").arg(cpap->getCPAPMode()); html+=tr("PAP Mode: %1<br/>").arg(day->getCPAPMode());
html+= cpap->getPressureSettings(); html+= day->getPressureSettings();
html+="</td></tr>\n"; html+="</td></tr>\n";
if ((cpap && cpap->settingExists(CPAP_BrokenSummary))) { if ((day->settingExists(CPAP_BrokenSummary))) {
html+="<tr><td>&nbsp;</td></tr>\n"; html+="<tr><td>&nbsp;</td></tr>\n";
html+=QString("<tr><td colspan=2><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+":</b> "+ tr("This day has missing pressure, mode and settings data.")); html+=QString("<tr><td colspan=2><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+":</b> "+ tr("This day has missing pressure, mode and settings data."));
} }
@ -1188,14 +1191,13 @@ QString Daily::getCPAPInformation(Day * cpap)
} }
QString Daily::getStatisticsInfo(Day * cpap,Day * oxi,Day *pos) QString Daily::getStatisticsInfo(Day * day)
{ {
if (!day) return QString();
QList<Day *> list; Machine *cpap = day->machine(MT_CPAP),
*oxi = day->machine(MT_OXIMETER),
list.push_back(cpap); *pos = day->machine(MT_POSITION);
list.push_back(oxi);
list.push_back(pos);
int mididx=p_profile->general->prefCalcMiddle(); int mididx=p_profile->general->prefCalcMiddle();
@ -1235,14 +1237,6 @@ QString Daily::getStatisticsInfo(Day * cpap,Day * oxi,Day *pos)
int ccnt=0; int ccnt=0;
EventDataType tmp,med,perc,mx,mn; EventDataType tmp,med,perc,mx,mn;
QList<Day *>::iterator di;
for (di=list.begin();di!=list.end();di++) {
Day * day=*di;
if (!day)
continue;
for (int i=0;i<numchans;i++) { for (int i=0;i<numchans;i++) {
ChannelID code=chans[i]; ChannelID code=chans[i];
@ -1291,17 +1285,17 @@ QString Daily::getStatisticsInfo(Day * cpap,Day * oxi,Day *pos)
.arg(mx,0,'f',2) .arg(mx,0,'f',2)
.arg(tooltip); .arg(tooltip);
ccnt++; ccnt++;
}
} }
if (GraphView->isEmpty() && ((ccnt>0) || (cpap && cpap->summaryOnly()))) { if (GraphView->isEmpty() && ((ccnt>0) || (cpap && day->summaryOnly()))) {
html+="<tr><td colspan=5>&nbsp;</td></tr>\n"; html+="<tr><td colspan=5>&nbsp;</td></tr>\n";
html+=QString("<tr><td colspan=5 align=center><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+"</b> "+ tr("This day just contains summary data, only limited information is available .")); html+=QString("<tr><td colspan=5 align=center><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+"</b> "+ tr("This day just contains summary data, only limited information is available ."));
} else if (cpap) { } else if (cpap) {
html+="<tr><td colspan=5>&nbsp;</td></tr>"; html+="<tr><td colspan=5>&nbsp;</td></tr>";
if ((cpap->machine->loaderName() == STR_MACH_ResMed) || ((cpap->machine->loaderName() == STR_MACH_PRS1) && (p_profile->cpap->resyncFromUserFlagging()))) { if ((cpap->loaderName() == STR_MACH_ResMed) || ((cpap->loaderName() == STR_MACH_PRS1) && (p_profile->cpap->resyncFromUserFlagging()))) {
int ttia = cpap->sum(CPAP_Obstructive) + cpap->sum(CPAP_ClearAirway) + cpap->sum(CPAP_Apnea) + cpap->sum(CPAP_Hypopnea); int ttia = day->sum(CPAP_Obstructive) + day->sum(CPAP_ClearAirway) + day->sum(CPAP_Apnea) + day->sum(CPAP_Hypopnea);
int h = ttia / 3600; int h = ttia / 3600;
int m = ttia / 60 % 60; int m = ttia / 60 % 60;
int s = ttia % 60; int s = ttia % 60;
@ -1311,28 +1305,31 @@ QString Daily::getStatisticsInfo(Day * cpap,Day * oxi,Day *pos)
} }
} }
float hours = day->hours(MT_CPAP);
if (p_profile->cpap->showLeakRedline()) { if (p_profile->cpap->showLeakRedline()) {
float rlt = cpap->timeAboveThreshold(CPAP_Leak, p_profile->cpap->leakRedline()) / 60.0; float rlt = day->timeAboveThreshold(CPAP_Leak, p_profile->cpap->leakRedline()) / 60.0;
float pc = 100.0 / cpap->hours() * rlt; float pc = 100.0 / hours * rlt;
html+="<tr><td colspan=3 align='left' bgcolor='white'><b>"+tr("Time over leak redline")+ html+="<tr><td colspan=3 align='left' bgcolor='white'><b>"+tr("Time over leak redline")+
QString("</b></td><td colspan=2 bgcolor='white'>%1%</td></tr>").arg(pc, 0, 'f', 3); QString("</b></td><td colspan=2 bgcolor='white'>%1%</td></tr>").arg(pc, 0, 'f', 3);
} }
int l = cpap->sum(CPAP_Ramp); int l = day->sum(CPAP_Ramp);
if (l > 0) { if (l > 0) {
html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("Total ramp time")+ html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("Total ramp time")+
QString("</td><td colspan=2 bgcolor='white'>%1:%2:%3</td></tr>").arg(l / 3600, 2, 10, QChar('0')).arg((l / 60) % 60, 2, 10, QChar('0')).arg(l % 60, 2, 10, QChar('0')); QString("</td><td colspan=2 bgcolor='white'>%1:%2:%3</td></tr>").arg(l / 3600, 2, 10, QChar('0')).arg((l / 60) % 60, 2, 10, QChar('0')).arg(l % 60, 2, 10, QChar('0'));
float v = (cpap->hours() - (float(l) / 3600.0)); float v = (hours - (float(l) / 3600.0));
int q = v * 3600.0; int q = v * 3600.0;
html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("Time outside of ramp")+ html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("Time outside of ramp")+
QString("</td><td colspan=2 bgcolor='white'>%1:%2:%3</td></tr>").arg(q / 3600, 2, 10, QChar('0')).arg((q / 60) % 60, 2, 10, QChar('0')).arg(q % 60, 2, 10, QChar('0')); QString("</td><td colspan=2 bgcolor='white'>%1:%2:%3</td></tr>").arg(q / 3600, 2, 10, QChar('0')).arg((q / 60) % 60, 2, 10, QChar('0')).arg(q % 60, 2, 10, QChar('0'));
EventDataType hc = cpap->count(CPAP_Hypopnea) - cpap->countInsideSpan(CPAP_Ramp, CPAP_Hypopnea); EventDataType hc = day->count(CPAP_Hypopnea) - day->countInsideSpan(CPAP_Ramp, CPAP_Hypopnea);
EventDataType oc = cpap->count(CPAP_Obstructive) - cpap->countInsideSpan(CPAP_Ramp, CPAP_Obstructive); EventDataType oc = day->count(CPAP_Obstructive) - day->countInsideSpan(CPAP_Ramp, CPAP_Obstructive);
EventDataType tc = cpap->count(CPAP_Hypopnea) + cpap->count(CPAP_Obstructive); EventDataType tc = day->count(CPAP_Hypopnea) + day->count(CPAP_Obstructive);
EventDataType ahi = (hc+oc) / v; EventDataType ahi = (hc+oc) / v;
// Not sure if i was trying to be funny, and left on my replication of Devilbiss's bug here... :P
html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("AHI excluding ramp")+ html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("AHI excluding ramp")+
QString("</td><td colspan=2 bgcolor='white'>%1</td></tr>").arg(ahi, 0, 'f', 2); QString("</td><td colspan=2 bgcolor='white'>%1</td></tr>").arg(ahi, 0, 'f', 2);
} }
@ -1355,17 +1352,14 @@ QString Daily::getEventBreakdown(Day * cpap)
return html; return html;
} }
QString Daily::getSleepTime(Day * cpap, Day * oxi) QString Daily::getSleepTime(Day * day)
{ {
//cpap, Day * oxi
QString html; QString html;
Day * day=nullptr; if (!day || (day->hours() < 0.0000001))
if (cpap && cpap->hours()>0)
day=cpap;
else if (oxi && oxi->hours()>0)
day=oxi;
else
return html; return html;
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"; html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
html+="<tr><td align='center'><b>"+STR_TR_Date+"</b></td><td align='center'><b>"+tr("Sleep")+"</b></td><td align='center'><b>"+tr("Wake")+"</b></td><td align='center'><b>"+STR_UNIT_Hours+"</b></td></tr>"; html+="<tr><td align='center'><b>"+STR_TR_Date+"</b></td><td align='center'><b>"+tr("Sleep")+"</b></td><td align='center'><b>"+tr("Wake")+"</b></td><td align='center'><b>"+STR_UNIT_Hours+"</b></td></tr>";
int tt=qint64(day->total_time())/1000L; int tt=qint64(day->total_time())/1000L;
@ -1392,38 +1386,46 @@ void Daily::Load(QDate date)
{ {
dateDisplay->setText("<i>"+date.toString(Qt::SystemLocaleLongDate)+"</i>"); dateDisplay->setText("<i>"+date.toString(Qt::SystemLocaleLongDate)+"</i>");
previous_date=date; previous_date=date;
Day *cpap=p_profile->GetDay(date,MT_CPAP);
Day *oxi=p_profile->GetDay(date,MT_OXIMETER); Day * day = p_profile->GetDay(date);
Day *stage=p_profile->GetDay(date,MT_SLEEPSTAGE); Machine *cpap = nullptr,
Day *posit=p_profile->GetDay(date,MT_POSITION); *oxi = nullptr,
*stage = nullptr,
*posit = nullptr;
if (day) {
cpap = day->machine(MT_CPAP);
oxi = day->machine(MT_OXIMETER);
stage = day->machine(MT_SLEEPSTAGE);
posit = day->machine(MT_POSITION);
}
if (!p_profile->session->cacheSessions()) { if (!p_profile->session->cacheSessions()) {
// Getting trashed on purge last day... // Getting trashed on purge last day...
// lastcpapday can get purged and be invalid // lastcpapday can get purged and be invalid
if (lastcpapday && (lastcpapday!=day)) {
if (lastcpapday && (lastcpapday!=cpap)) {
for (QList<Session *>::iterator s=lastcpapday->begin();s!=lastcpapday->end();++s) { for (QList<Session *>::iterator s=lastcpapday->begin();s!=lastcpapday->end();++s) {
(*s)->TrashEvents(); (*s)->TrashEvents();
} }
} }
} }
if ((cpap && oxi) && oxi->hasEnabledSessions()) { // Don't really see a point in unlinked oximetery sessions anymore... All I can say is BLEH...
int gr; // if ((cpap && oxi) && day->hasEnabledSessions(MT_OXIMETER)) {
// int gr;
if (qAbs(cpap->first() - oxi->first())>30000) { // if (qAbs(day->first(MT_CPAP) - day->first(MT_OXIMETER)) > 30000) {
mainwin->Notify(tr("Oximetry data exists for this day, but its timestamps are too different, so the Graphs will not be linked."),"",3000); // mainwin->Notify(tr("Oximetry data exists for this day, but its timestamps are too different, so the Graphs will not be linked."),"",3000);
gr=1; // gr=1;
} else // } else
gr=0; // gr=0;
(*GraphView)[schema::channel[OXI_Pulse].code()]->setGroup(gr); // (*GraphView)[schema::channel[OXI_Pulse].code()]->setGroup(gr);
(*GraphView)[schema::channel[OXI_SPO2].code()]->setGroup(gr); // (*GraphView)[schema::channel[OXI_SPO2].code()]->setGroup(gr);
(*GraphView)[schema::channel[OXI_Plethy].code()]->setGroup(gr); // (*GraphView)[schema::channel[OXI_Plethy].code()]->setGroup(gr);
} // }
lastcpapday=cpap; lastcpapday=day;
QString html="<html><head><style type='text/css'>" QString html="<html><head><style type='text/css'>"
"p,a,td,body { font-family: '"+QApplication::font().family()+"'; }" "p,a,td,body { font-family: '"+QApplication::font().family()+"'; }"
@ -1443,20 +1445,27 @@ void Daily::Load(QDate date)
"<body leftmargin=0 rightmargin=0 topmargin=0 marginwidth=0 marginheight=0>"; "<body leftmargin=0 rightmargin=0 topmargin=0 marginwidth=0 marginheight=0>";
QString tmp; QString tmp;
UpdateOXIGraphs(oxi); if (day) {
UpdateCPAPGraphs(cpap); day->OpenEvents();
UpdateSTAGEGraphs(stage); }
UpdatePOSGraphs(posit); GraphView->setDay(day);
UpdateEventsTree(ui->treeWidget,cpap);
// UpdateOXIGraphs(oxi);
// UpdateCPAPGraphs(cpap);
// UpdateSTAGEGraphs(stage);
// UpdatePOSGraphs(posit);
UpdateEventsTree(ui->treeWidget, day);
// FIXME: // FIXME:
// Generating entire statistics because bookmarks may have changed.. (This updates the side panel too) // Generating entire statistics because bookmarks may have changed.. (This updates the side panel too)
mainwin->GenerateStatistics(); mainwin->GenerateStatistics();
snapGV->setDay(cpap); snapGV->setDay(day);
GraphView->ResetBounds(false); // GraphView->ResetBounds(false);
// wtf is hiding the scrollbars for???
if (!cpap && !oxi) { if (!cpap && !oxi) {
scrollbar->hide(); scrollbar->hide();
} else { } else {
@ -1471,11 +1480,10 @@ void Daily::Load(QDate date)
updateGraphCombo(); updateGraphCombo();
ui->eventsCombo->clear(); ui->eventsCombo->clear();
if (cpap) {
quint32 chans = schema::SPAN | schema::FLAG | schema::MINOR_FLAG; quint32 chans = schema::SPAN | schema::FLAG | schema::MINOR_FLAG;
if (p_profile->general->showUnknownFlags()) chans |= schema::UNKNOWN; if (p_profile->general->showUnknownFlags()) chans |= schema::UNKNOWN;
QList<ChannelID> available = cpap->getSortedMachineChannels(chans); QList<ChannelID> available = day->getSortedMachineChannels(chans);
for (int i=0; i < available.size(); ++i) { for (int i=0; i < available.size(); ++i) {
ChannelID code = available.at(i); ChannelID code = available.at(i);
@ -1484,13 +1492,12 @@ void Daily::Load(QDate date)
ui->eventsCombo->setItemData(i, chan.fullname(), Qt::ToolTipRole); ui->eventsCombo->setItemData(i, chan.fullname(), Qt::ToolTipRole);
} }
}
if (cpap) { if (cpap) {
//QHash<schema::ChanType, QList<schema::Channel *> > list; //QHash<schema::ChanType, QList<schema::Channel *> > list;
float hours=cpap->hours(); float hours=day->hours(MT_CPAP);
if (GraphView->isEmpty() && (hours>0)) { if (GraphView->isEmpty() && (hours>0)) {
if (!p_profile->hasChannel(CPAP_Obstructive) && !p_profile->hasChannel(CPAP_Hypopnea)) { if (!p_profile->hasChannel(CPAP_Obstructive) && !p_profile->hasChannel(CPAP_Hypopnea)) {
GraphView->setEmptyText(tr("No Graphs :(")); GraphView->setEmptyText(tr("No Graphs :("));
@ -1499,12 +1506,12 @@ void Daily::Load(QDate date)
} }
} }
mode=(CPAPMode)(int)cpap->settings_max(CPAP_Mode); mode=(CPAPMode)(int)day->settings_max(CPAP_Mode);
modestr=schema::channel[CPAP_Mode].m_options[mode]; modestr=schema::channel[CPAP_Mode].m_options[mode];
EventDataType ahi=(cpap->count(CPAP_Obstructive)+cpap->count(CPAP_Hypopnea)+cpap->count(CPAP_ClearAirway)+cpap->count(CPAP_Apnea)); EventDataType ahi=(day->count(CPAP_Obstructive)+day->count(CPAP_Hypopnea)+day->count(CPAP_ClearAirway)+day->count(CPAP_Apnea));
if (p_profile->general->calculateRDI()) ahi+=cpap->count(CPAP_RERA); if (p_profile->general->calculateRDI()) ahi+=day->count(CPAP_RERA);
ahi/=hours; ahi/=hours;
if (!isBrick && hours>0) { if (!isBrick && hours>0) {
@ -1520,8 +1527,8 @@ void Daily::Load(QDate date)
.arg("#F88017").arg(COLOR_Text.name()).arg(ahiname).arg(schema::channel[ahichan].fullname()).arg(ahi,0,'f',2); .arg("#F88017").arg(COLOR_Text.name()).arg(ahiname).arg(schema::channel[ahichan].fullname()).arg(ahi,0,'f',2);
html+="</tr>\n"; html+="</tr>\n";
html+="</table>\n"; html+="</table>\n";
html+=getCPAPInformation(cpap); html+=getCPAPInformation(day);
html+=getSleepTime(cpap,oxi); html+=getSleepTime(day);
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"; html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
@ -1531,7 +1538,7 @@ void Daily::Load(QDate date)
if (p_profile->general->showUnknownFlags()) zchans |= schema::UNKNOWN; if (p_profile->general->showUnknownFlags()) zchans |= schema::UNKNOWN;
if (show_minors) zchans |= schema::MINOR_FLAG; if (show_minors) zchans |= schema::MINOR_FLAG;
QList<ChannelID> available = cpap->getSortedMachineChannels(zchans); QList<ChannelID> available = day->getSortedMachineChannels(zchans);
EventDataType val; EventDataType val;
QHash<ChannelID, EventDataType> values; QHash<ChannelID, EventDataType> values;
@ -1541,10 +1548,10 @@ void Daily::Load(QDate date)
if (!chan.enabled()) continue; if (!chan.enabled()) continue;
QString data; QString data;
if (chan.type() == schema::SPAN) { if (chan.type() == schema::SPAN) {
val = (100.0 / hours)*(cpap->sum(code)/3600.0); val = (100.0 / hours)*(day->sum(code)/3600.0);
data = QString("%1%").arg(val,0,'f',2); data = QString("%1%").arg(val,0,'f',2);
} else { } else {
val = cpap->count(code) / hours; val = day->count(code) / hours;
data = QString("%1").arg(val,0,'f',2); data = QString("%1").arg(val,0,'f',2);
} }
values[code] = val; values[code] = val;
@ -1588,13 +1595,13 @@ void Daily::Load(QDate date)
} else { } else {
html += "<tr><td align=center>Unable to display Pie Chart on this system</td></tr>\n"; html += "<tr><td align=center>Unable to display Pie Chart on this system</td></tr>\n";
} }
} else if (cpap->channelHasData(CPAP_Obstructive) } else if (day->channelHasData(CPAP_Obstructive)
|| cpap->channelHasData(CPAP_Hypopnea) || day->channelHasData(CPAP_Hypopnea)
|| cpap->channelHasData(CPAP_ClearAirway) || day->channelHasData(CPAP_ClearAirway)
|| cpap->channelHasData(CPAP_RERA) || day->channelHasData(CPAP_RERA)
|| cpap->channelHasData(CPAP_Apnea) || day->channelHasData(CPAP_Apnea)
|| cpap->channelHasData(CPAP_FlowLimit) || day->channelHasData(CPAP_FlowLimit)
|| cpap->channelHasData(CPAP_SensAwake) || day->channelHasData(CPAP_SensAwake)
) { ) {
html += "<tr><td align=center><img src=\"qrc:/docs/0.0.gif\"></td></tr>\n"; html += "<tr><td align=center><img src=\"qrc:/docs/0.0.gif\"></td></tr>\n";
} }
@ -1606,7 +1613,7 @@ void Daily::Load(QDate date)
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"; html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
if (!isBrick) { if (!isBrick) {
html+="<tr><td colspan='5'>&nbsp;</td></tr>\n"; html+="<tr><td colspan='5'>&nbsp;</td></tr>\n";
if (cpap->size()>0) { if (day->size()>0) {
html+="<tr><td colspan='5' align='center'><b><h2>"+tr("Sessions all off!")+"</h2></b></td></tr>"; html+="<tr><td colspan='5' align='center'><b><h2>"+tr("Sessions all off!")+"</h2></b></td></tr>";
html+="<tr><td colspan='5' align='center'><i>"+tr("Sessions exist for this day but are switched off.")+"</i></td></tr>\n"; html+="<tr><td colspan='5' align='center'><i>"+tr("Sessions exist for this day but are switched off.")+"</i></td></tr>\n";
} else { } else {
@ -1624,14 +1631,14 @@ void Daily::Load(QDate date)
html+="<hr/>\n"; html+="<hr/>\n";
} // if (!CPAP) } // if (!CPAP)
else html+=getSleepTime(cpap,oxi); else html+=getSleepTime(day);
if ((cpap && !isBrick && (cpap->hours()>0)) || oxi || posit) { if ((cpap && !isBrick && (day->hours()>0)) || oxi || posit) {
html+=getStatisticsInfo(cpap,oxi,posit); html+=getStatisticsInfo(day);
} else { } else {
if (cpap && cpap->hours()==0) { if (cpap && day->hours(MT_CPAP)<0.0000001) {
} else { } else {
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"; html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
html+="<tr><td colspan=5 align=center><i>"+tr("No data available")+"</i></td></tr>\n"; html+="<tr><td colspan=5 align=center><i>"+tr("No data available")+"</i></td></tr>\n";
@ -1641,10 +1648,11 @@ void Daily::Load(QDate date)
} }
} }
if (day) {
html+=getOximeterInformation(oxi); html+=getOximeterInformation(day);
html+=getMachineSettings(cpap); html+=getMachineSettings(day);
html+=getSessionInformation(cpap,oxi,stage,posit); html+=getSessionInformation(day);
}
html+="</body></html>"; html+="</body></html>";
@ -1662,8 +1670,9 @@ void Daily::Load(QDate date)
connect(sessbar, SIGNAL(sessionClicked(Session*)), this, SLOT(doToggleSession(Session*))); connect(sessbar, SIGNAL(sessionClicked(Session*)), this, SLOT(doToggleSession(Session*)));
int c=0; int c=0;
for (i=cpap->begin();i!=cpap->end();++i) { for (i=day->begin();i!=day->end();++i) {
Session * s=*i; Session * s=*i;
if ((*s).machine()->type() == MT_CPAP)
sessbar->add(s, cols[c % maxcolors]); sessbar->add(s, cols[c % maxcolors]);
c++; c++;
} }
@ -1941,10 +1950,13 @@ Session * Daily::CreateJournalSession(QDate date)
info.brand = "Journal"; info.brand = "Journal";
info.type = MT_JOURNAL; info.type = MT_JOURNAL;
m->setInfo(info); m->setInfo(info);
m->setType(MT_JOURNAL);
p_profile->AddMachine(m); p_profile->AddMachine(m);
} }
Session *sess=new Session(m,0); Session *sess=new Session(m,0);
qint64 st,et; qint64 st,et;
Day *cday=p_profile->GetDay(date,MT_CPAP); Day *cday=p_profile->GetDay(date,MT_CPAP);
if (cday) { if (cday) {
st=cday->first(); st=cday->first();
@ -1962,14 +1974,13 @@ Session * Daily::CreateJournalSession(QDate date)
} }
Session * Daily::GetJournalSession(QDate date) // Get the first journal session Session * Daily::GetJournalSession(QDate date) // Get the first journal session
{ {
Day *journal=p_profile->GetDay(date,MT_JOURNAL); Day *day=p_profile->addDay(date);
if (!journal)
return nullptr; //CreateJournalSession(date); Session * session = day->firstSession(MT_JOURNAL);
QList<Session *>::iterator s; if (!session) {
s=journal->begin(); session = CreateJournalSession(date);
if (s!=journal->end()) }
return *s; return session;
return nullptr;
} }
void Daily::UpdateCPAPGraphs(Day *day) void Daily::UpdateCPAPGraphs(Day *day)

View File

@ -314,13 +314,13 @@ private:
void updateGraphCombo(); void updateGraphCombo();
QString getSessionInformation(Day *cpap, Day *oxi, Day *stage, Day *posit); QString getSessionInformation(Day *);
QString getMachineSettings(Day *cpap); QString getMachineSettings(Day *);
QString getStatisticsInfo(Day *cpap, Day *oxi, Day *pos); QString getStatisticsInfo(Day *);
QString getCPAPInformation(Day *cpap); QString getCPAPInformation(Day *);
QString getOximeterInformation(Day *oxi); QString getOximeterInformation(Day *);
QString getEventBreakdown(Day *cpap); QString getEventBreakdown(Day *);
QString getSleepTime(Day *cpap, Day *oxi); QString getSleepTime(Day *);
QHash<QString, gGraph *> graphlist; QHash<QString, gGraph *> graphlist;

View File

@ -1180,7 +1180,7 @@ void MainWindow::updateFavourites()
if (journal) { if (journal) {
if (journal->size() > 0) { if (journal->size() > 0) {
Session *sess = (*journal)[0]; Session *sess = journal->firstSession(MT_JOURNAL);
QString tmp; QString tmp;
bool filtered = !bookmarkFilter.isEmpty(); bool filtered = !bookmarkFilter.isEmpty();
bool found = !filtered; bool found = !filtered;
@ -1939,11 +1939,10 @@ void MainWindow::on_actionPurge_Current_Day_triggered()
QDate date = getDaily()->getDate(); QDate date = getDaily()->getDate();
getDaily()->Unload(date); getDaily()->Unload(date);
Day *day = p_profile->GetDay(date, MT_CPAP); Day *day = p_profile->GetDay(date, MT_CPAP);
Machine *m; Machine *cpap = nullptr;
if (day) cpap = day->machine(MT_CPAP);
if (day) {
m = day->machine;
if (cpap) {
QList<Session *>::iterator s; QList<Session *>::iterator s;
QList<Session *> list; QList<Session *> list;
@ -1956,13 +1955,13 @@ void MainWindow::on_actionPurge_Current_Day_triggered()
QHash<QString, SessionID> skipfiles; QHash<QString, SessionID> skipfiles;
// Read the already imported file list // Read the already imported file list
QFile impfile(m->getDataPath()+"/imported_files.csv"); QFile impfile(cpap->getDataPath()+"/imported_files.csv");
if (impfile.exists()) { if (impfile.exists()) {
if (impfile.open(QFile::ReadOnly)) { if (impfile.open(QFile::ReadOnly)) {
QTextStream impstream(&impfile); QTextStream impstream(&impfile);
QString serial; QString serial;
impstream >> serial; impstream >> serial;
if (m->serial() == serial) { if (cpap->serial() == serial) {
QString line, file, str; QString line, file, str;
SessionID sid; SessionID sid;
bool ok; bool ok;
@ -1984,7 +1983,7 @@ void MainWindow::on_actionPurge_Current_Day_triggered()
// Rewrite the file without the sessions being removed. // Rewrite the file without the sessions being removed.
if (impfile.open(QFile::WriteOnly)) { if (impfile.open(QFile::WriteOnly)) {
QTextStream out(&impfile); QTextStream out(&impfile);
out << m->serial(); out << cpap->serial();
QHash<QString, SessionID>::iterator skit; QHash<QString, SessionID>::iterator skit;
QHash<QString, SessionID>::iterator skit_end = skipfiles.end(); QHash<QString, SessionID>::iterator skit_end = skipfiles.end();
for (skit = skipfiles.begin(); skit != skit_end; ++skit) { for (skit = skipfiles.begin(); skit != skit_end; ++skit) {

View File

@ -433,7 +433,7 @@ void OximeterImport::on_liveImportButton_clicked()
oximodule->Open("live"); oximodule->Open("live");
ui->stopButton->setVisible(true); ui->stopButton->setVisible(true);
dummyday = new Day(mach); dummyday = new Day();
quint32 starttime = oximodule->startTime().toTime_t(); quint32 starttime = oximodule->startTime().toTime_t();
ti = qint64(starttime) * 1000L; ti = qint64(starttime) * 1000L;
@ -445,7 +445,7 @@ void OximeterImport::on_liveImportButton_clicked()
ELplethy->setFirst(start_ti); ELplethy->setFirst(start_ti);
session->really_set_first(start_ti); session->really_set_first(start_ti);
dummyday->AddSession(session); dummyday->addSession(session);
plethyChart->setMinX(start_ti); plethyChart->setMinX(start_ti);
plethyGraph->SetMinX(start_ti); plethyGraph->SetMinX(start_ti);

View File

@ -158,19 +158,21 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
if (bounds.height() > maxy) { maxy = bounds.height(); } if (bounds.height() > maxy) { maxy = bounds.height(); }
} }
Day *cpap = nullptr, *oxi = nullptr; Machine *cpap = nullptr, *oxi = nullptr;
int graph_slots = 0; int graph_slots = 0;
Day * day = p_profile->GetGoodDay(mainwin->getDaily()->getDate(), MT_CPAP);
if (day) cpap = day->machine(MT_CPAP);
if (name == STR_TR_Daily) { if (name == STR_TR_Daily) {
cpap = p_profile->GetGoodDay(date, MT_CPAP);
oxi = p_profile->GetGoodDay(date, MT_OXIMETER);
QString cpapinfo = date.toString(Qt::SystemLocaleLongDate) + "\n\n"; QString cpapinfo = date.toString(Qt::SystemLocaleLongDate) + "\n\n";
if (cpap) { if (cpap) {
time_t f = cpap->first() / 1000L; time_t f = day->first(MT_CPAP) / 1000L;
time_t l = cpap->last() / 1000L; time_t l = day->last(MT_CPAP) / 1000L;
int tt = qint64(cpap->total_time()) / 1000L; int tt = qint64(day->total_time(MT_CPAP)) / 1000L;
int h = tt / 3600; int h = tt / 3600;
int m = (tt / 60) % 60; int m = (tt / 60) % 60;
int s = tt % 60; int s = tt % 60;
@ -186,29 +188,29 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
// submodel = "\n" + cpap->machine->info.modeproperties[STR_PROP_SubModel]; // submodel = "\n" + cpap->machine->info.modeproperties[STR_PROP_SubModel];
// } // }
cpapinfo += cpap->machine->brand() + " " + cpapinfo += cpap->brand() + " " +
cpap->machine->model() + submodel; cpap->model() + submodel;
CPAPMode mode = (CPAPMode)(int)cpap->settings_max(CPAP_Mode); CPAPMode mode = (CPAPMode)(int)day->settings_max(CPAP_Mode);
cpapinfo += "\n" + STR_TR_Mode + ": "; cpapinfo += "\n" + STR_TR_Mode + ": ";
if (mode == MODE_CPAP) { if (mode == MODE_CPAP) {
EventDataType min = round(cpap->settings_wavg(CPAP_Pressure) * 2) / 2.0; EventDataType min = round(day->settings_wavg(CPAP_Pressure) * 2) / 2.0;
cpapinfo += STR_TR_CPAP + " " + QString::number(min) + STR_UNIT_CMH2O; cpapinfo += STR_TR_CPAP + " " + QString::number(min) + STR_UNIT_CMH2O;
} else if (mode == MODE_APAP) { } else if (mode == MODE_APAP) {
EventDataType min = cpap->settings_min(CPAP_PressureMin); EventDataType min = day->settings_min(CPAP_PressureMin);
EventDataType max = cpap->settings_max(CPAP_PressureMax); EventDataType max = day->settings_max(CPAP_PressureMax);
cpapinfo += STR_TR_APAP + " " + QString::number(min) + "-" + QString::number(max) + STR_UNIT_CMH2O; cpapinfo += STR_TR_APAP + " " + QString::number(min) + "-" + QString::number(max) + STR_UNIT_CMH2O;
} else if (mode == MODE_BILEVEL_FIXED) { } else if (mode == MODE_BILEVEL_FIXED) {
EventDataType epap = cpap->settings_min(CPAP_EPAP); EventDataType epap = day->settings_min(CPAP_EPAP);
EventDataType ipap = cpap->settings_max(CPAP_IPAP); EventDataType ipap = day->settings_max(CPAP_IPAP);
EventDataType ps = cpap->settings_max(CPAP_PS); EventDataType ps = day->settings_max(CPAP_PS);
cpapinfo += STR_TR_BiLevel + cpapinfo += STR_TR_BiLevel +
QString("\n" + STR_TR_EPAP + ": %1 " + STR_TR_IPAP + ": %2 %3\n" + STR_TR_PS + ": %4") QString("\n" + STR_TR_EPAP + ": %1 " + STR_TR_IPAP + ": %2 %3\n" + STR_TR_PS + ": %4")
.arg(epap, 0, 'f', 1).arg(ipap, 0, 'f', 1).arg(STR_UNIT_CMH2O).arg(ps, 0, 'f', 1); .arg(epap, 0, 'f', 1).arg(ipap, 0, 'f', 1).arg(STR_UNIT_CMH2O).arg(ps, 0, 'f', 1);
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) { } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
EventDataType epap = cpap->settings_min(CPAP_EPAP); EventDataType epap = day->settings_min(CPAP_EPAP);
EventDataType ipap = cpap->settings_max(CPAP_IPAP); EventDataType ipap = day->settings_max(CPAP_IPAP);
EventDataType ps = cpap->settings_max(CPAP_PS); EventDataType ps = day->settings_max(CPAP_PS);
cpapinfo += STR_TR_BiLevel + cpapinfo += STR_TR_BiLevel +
QString("\n" + QObject::tr("Range")+ ": %1-%2 %3 " + QObject::tr("Fixed %1").arg(STR_TR_PS) + ": %4") QString("\n" + QObject::tr("Range")+ ": %1-%2 %3 " + QObject::tr("Fixed %1").arg(STR_TR_PS) + ": %4")
.arg(epap, 0, 'f', 1).arg(ipap, 0, 'f', 1).arg(STR_UNIT_CMH2O).arg(ps, 0, 'f', 1); .arg(epap, 0, 'f', 1).arg(ipap, 0, 'f', 1).arg(STR_UNIT_CMH2O).arg(ps, 0, 'f', 1);
@ -221,11 +223,11 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
QString("\n" + QObject::tr("Fixed %1").arg(STR_TR_EPAP) + ": %1 %3" + QObject::tr("Max %1").arg(STR_TR_IPAP) + ": %2 %3\n" + QObject::tr("Variable %1").arg(STR_TR_PS) + ": %4-%5") QString("\n" + QObject::tr("Fixed %1").arg(STR_TR_EPAP) + ": %1 %3" + QObject::tr("Max %1").arg(STR_TR_IPAP) + ": %2 %3\n" + QObject::tr("Variable %1").arg(STR_TR_PS) + ": %4-%5")
.arg(epap, 0, 'f', 1).arg(ipap, 0, 'f', 1).arg(STR_UNIT_CMH2O).arg(psl,0,'f',1).arg(psh,0,'f',1); .arg(epap, 0, 'f', 1).arg(ipap, 0, 'f', 1).arg(STR_UNIT_CMH2O).arg(psl,0,'f',1).arg(psh,0,'f',1);
} */else if (mode == MODE_ASV) { } */else if (mode == MODE_ASV) {
EventDataType epap = cpap->settings_min(CPAP_EPAP); EventDataType epap = day->settings_min(CPAP_EPAP);
EventDataType low = cpap->settings_min(CPAP_IPAPLo); EventDataType low = day->settings_min(CPAP_IPAPLo);
EventDataType high = cpap->settings_max(CPAP_IPAPHi); EventDataType high = day->settings_max(CPAP_IPAPHi);
EventDataType psl = cpap->settings_min(CPAP_PSMin); EventDataType psl = day->settings_min(CPAP_PSMin);
EventDataType psh = cpap->settings_max(CPAP_PSMax); EventDataType psh = day->settings_max(CPAP_PSMax);
cpapinfo += STR_TR_ASV + QString("\n" + STR_TR_EPAP + ": %1 " + STR_TR_IPAP + ": %2 - %3 %4\n" + cpapinfo += STR_TR_ASV + QString("\n" + STR_TR_EPAP + ": %1 " + STR_TR_IPAP + ": %2 - %3 %4\n" +
STR_TR_PS + ": %5 / %6") STR_TR_PS + ": %5 / %6")
.arg(epap, 0, 'f', 1) .arg(epap, 0, 'f', 1)
@ -236,24 +238,25 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
.arg(psh, 0, 'f', 1); .arg(psh, 0, 'f', 1);
} else { cpapinfo += STR_TR_Unknown; } } else { cpapinfo += STR_TR_Unknown; }
float ahi = (cpap->count(CPAP_Obstructive) + cpap->count(CPAP_Hypopnea) + cpap->count( float ahi = (day->count(CPAP_Obstructive) + day->count(CPAP_Hypopnea) +
CPAP_ClearAirway) + cpap->count(CPAP_Apnea)); day->count(CPAP_ClearAirway) + day->count(CPAP_Apnea));
if (p_profile->general->calculateRDI()) { ahi += cpap->count(CPAP_RERA); } if (p_profile->general->calculateRDI()) { ahi += day->count(CPAP_RERA); }
ahi /= cpap->hours(); float hours = day->hours(MT_CPAP);
float csr = (100.0 / cpap->hours()) * (cpap->sum(CPAP_CSR) / 3600.0); ahi /= hours;
float uai = cpap->count(CPAP_Apnea) / cpap->hours(); float csr = (100.0 / hours) * (day->sum(CPAP_CSR) / 3600.0);
float oai = cpap->count(CPAP_Obstructive) / cpap->hours(); float uai = day->count(CPAP_Apnea) / hours;
float hi = (cpap->count(CPAP_ExP) + cpap->count(CPAP_Hypopnea)) / cpap->hours(); float oai = day->count(CPAP_Obstructive) / hours;
float cai = cpap->count(CPAP_ClearAirway) / cpap->hours(); float hi = (day->count(CPAP_ExP) + day->count(CPAP_Hypopnea)) / hours;
float rei = cpap->count(CPAP_RERA) / cpap->hours(); float cai = day->count(CPAP_ClearAirway) / hours;
float vsi = cpap->count(CPAP_VSnore) / cpap->hours(); float rei = day->count(CPAP_RERA) / hours;
float fli = cpap->count(CPAP_FlowLimit) / cpap->hours(); float vsi = day->count(CPAP_VSnore) / hours;
// float sai = cpap->count(CPAP_SensAwake) / cpap->hours(); float fli = day->count(CPAP_FlowLimit) / hours;
float nri = cpap->count(CPAP_NRI) / cpap->hours(); // float sai = day->count(CPAP_SensAwake) / hours;
float lki = cpap->count(CPAP_LeakFlag) / cpap->hours(); float nri = day->count(CPAP_NRI) / hours;
float exp = cpap->count(CPAP_ExP) / cpap->hours(); float lki = day->count(CPAP_LeakFlag) / hours;
float exp = day->count(CPAP_ExP) / hours;
int piesize = (2048.0 / 8.0) * 1.3; // 1.5" in size int piesize = (2048.0 / 8.0) * 1.3; // 1.5" in size
//float fscale=font_scale; //float fscale=font_scale;
@ -303,13 +306,13 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
stats = QObject::tr("AI=%1 HI=%2 CAI=%3 ").arg(oai, 0, 'f', 2).arg(hi, 0, 'f', 2).arg(cai, 0, 'f', stats = QObject::tr("AI=%1 HI=%2 CAI=%3 ").arg(oai, 0, 'f', 2).arg(hi, 0, 'f', 2).arg(cai, 0, 'f',
2); 2);
if (cpap->machine->loaderName() == STR_MACH_PRS1) { if (cpap->loaderName() == STR_MACH_PRS1) {
stats += QObject::tr("REI=%1 VSI=%2 FLI=%3 PB/CSR=%4%%") stats += QObject::tr("REI=%1 VSI=%2 FLI=%3 PB/CSR=%4%%")
.arg(rei, 0, 'f', 2).arg(vsi, 0, 'f', 2) .arg(rei, 0, 'f', 2).arg(vsi, 0, 'f', 2)
.arg(fli, 0, 'f', 2).arg(csr, 0, 'f', 2); .arg(fli, 0, 'f', 2).arg(csr, 0, 'f', 2);
} else if (cpap->machine->loaderName() == STR_MACH_ResMed) { } else if (cpap->loaderName() == STR_MACH_ResMed) {
stats += QObject::tr("UAI=%1 ").arg(uai, 0, 'f', 2); stats += QObject::tr("UAI=%1 ").arg(uai, 0, 'f', 2);
} else if (cpap->machine->loaderName() == STR_MACH_Intellipap) { } else if (cpap->loaderName() == STR_MACH_Intellipap) {
stats += QObject::tr("NRI=%1 LKI=%2 EPI=%3").arg(nri, 0, 'f', 2).arg(lki, 0, 'f', 2).arg(exp, 0, stats += QObject::tr("NRI=%1 LKI=%2 EPI=%3").arg(nri, 0, 'f', 2).arg(lki, 0, 'f', 2).arg(exp, 0,
'f', 2); 'f', 2);
} }
@ -418,11 +421,11 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
if (!g->visible()) { continue; } if (!g->visible()) { continue; }
if (cpap) { if (cpap) {
st = cpap->first(); st = day->first(MT_CPAP);
et = cpap->last(); et = day->last(MT_CPAP);
} else if (oxi) { } else if (oxi) {
st = oxi->first(); st = day->first(MT_OXIMETER);
et = oxi->last(); et = day->last(MT_OXIMETER);
} }
if (g->name() == schema::channel[CPAP_FlowRate].code()) { if (g->name() == schema::channel[CPAP_FlowRate].code()) {
@ -459,22 +462,22 @@ void Report::PrintReport(gGraphView *gv, QString name, QDate date)
if (cpap && flow && !flow->isEmpty() && flow->visible()) { if (cpap && flow && !flow->isEmpty() && flow->visible()) {
labels.push_back(EntireDay); labels.push_back(EntireDay);
start.push_back(cpap->first()); start.push_back(day->first(MT_CPAP));
end.push_back(cpap->last()); end.push_back(day->last(MT_CPAP));
graphs.push_back(flow); graphs.push_back(flow);
} }
if (oxi && spo2 && !spo2->isEmpty() && spo2->visible()) { if (oxi && spo2 && !spo2->isEmpty() && spo2->visible()) {
labels.push_back(EntireDay); labels.push_back(EntireDay);
start.push_back(oxi->first()); start.push_back(day->first(MT_OXIMETER));
end.push_back(oxi->last()); end.push_back(day->last(MT_OXIMETER));
graphs.push_back(spo2); graphs.push_back(spo2);
} }
if (oxi && pulse && !pulse->isEmpty() && pulse->visible()) { if (oxi && pulse && !pulse->isEmpty() && pulse->visible()) {
labels.push_back(EntireDay); labels.push_back(EntireDay);
start.push_back(oxi->first()); start.push_back(day->first(MT_OXIMETER));
end.push_back(oxi->last()); end.push_back(day->last(MT_OXIMETER));
graphs.push_back(pulse); graphs.push_back(pulse);
} }

View File

@ -756,12 +756,12 @@ QString Statistics::GenerateHTML()
CPAPLoader * loader = nullptr; CPAPLoader * loader = nullptr;
if (day) loader = dynamic_cast<CPAPLoader *>(day->machine->loader()); if (day) loader = dynamic_cast<CPAPLoader *>(day->machine(MT_CPAP)->loader());
if (day && loader) { if (day && loader) {
lastchanged = false; lastchanged = false;
hours = day->hours(); hours = day->hours(MT_CPAP);
if (hours > p_profile->cpap->complianceHours()) { if (hours > p_profile->cpap->complianceHours()) {
compliant++; compliant++;
@ -781,7 +781,7 @@ QString Statistics::GenerateHTML()
if (mode ==0) { if (mode ==0) {
mode = (CPAPMode)(int)round(day->settings_wavg(CPAP_Mode)); mode = (CPAPMode)(int)round(day->settings_wavg(CPAP_Mode));
} }
mach = day->machine; mach = day->machine(MT_CPAP);
min = max = ps = pshi = maxipap = 0; min = max = ps = pshi = maxipap = 0;

View File

@ -122,20 +122,23 @@ QString GenerateWelcomeHTML()
html += "<p>" + QObject::tr("It might be a good idea to check preferences first,</br>as there are some options that affect import.")+"</p>" html += "<p>" + QObject::tr("It might be a good idea to check preferences first,</br>as there are some options that affect import.")+"</p>"
"<p>" + QObject::tr("First import can take a few minutes.") + "</p>"; "<p>" + QObject::tr("First import can take a few minutes.") + "</p>";
} else { } else {
if (havecpapdata) {
QString cpapimage = "";
QDate date = p_profile->LastDay(MT_CPAP); QDate date = p_profile->LastDay(MT_CPAP);
Day *day = p_profile->GetDay(date, MT_CPAP); Day *day = p_profile->GetDay(date, MT_CPAP);
if (day) {
if (day->machine->loaderName() == STR_MACH_ResMed) cpapimage = "qrc:/icons/rms9.png"; if (havecpapdata && day) {
else if (day->machine->loaderName() == STR_MACH_PRS1) cpapimage = "qrc:/icons/prs1.png"; QString cpapimage = "";
else if (day->machine->loaderName() == STR_MACH_Intellipap) cpapimage = "qrc:/icons/intellipap.png";
Machine * cpap = day->machine(MT_CPAP);
if (cpap) {
if (cpap->loaderName() == STR_MACH_ResMed) cpapimage = "qrc:/icons/rms9.png";
else if (cpap->loaderName() == STR_MACH_PRS1) cpapimage = "qrc:/icons/prs1.png";
else if (cpap->loaderName() == STR_MACH_Intellipap) cpapimage = "qrc:/icons/intellipap.png";
} }
html += "<table cellpadding=4><tr><td><img src='"+cpapimage+"' width=160px><br/>"; html += "<table cellpadding=4><tr><td><img src='"+cpapimage+"' width=160px><br/>";
html+="</td><td align=center><table cellpadding=4 class=curved2 title=\""+QObject::tr("Click this box to see this in daily view.")+"\"><tr>"+ html+="</td><td align=center><table cellpadding=4 class=curved2 title=\""+QObject::tr("Click this box to see this in daily view.")+"\"><tr>"+
QString("<td align=center onmouseover='ChangeColor(this, \"#efefa0\");' onmouseout='ChangeColor(this, \"#ffffc0\");' onclick='alert(\"daily=%1\");'>").arg(date.toString(Qt::ISODate))+"<b>"+ QString("<td align=center onmouseover='ChangeColor(this, \"#efefa0\");' onmouseout='ChangeColor(this, \"#ffffc0\");' onclick='alert(\"daily=%1\");'>").arg(date.toString(Qt::ISODate))+"<b>"+
QObject::tr("The last time you used your %1...").arg(day->machine->brand()+" "+day->machine->model())+"</b><br/>"; QObject::tr("The last time you used your %1...").arg(cpap->brand()+" "+cpap->model())+"</b><br/>";
int daysto = date.daysTo(QDate::currentDate()); int daysto = date.daysTo(QDate::currentDate());
QString daystring; QString daystring;