mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-08 20:20:44 +00:00
Some machine pixmap stuff, use gzip compatible Summaries.xml, preliminary PRS1 .006 oximetery parser
This commit is contained in:
parent
b3f49f1edb
commit
429fcb64a1
@ -3170,6 +3170,7 @@ const quint16 gvversion = 4;
|
|||||||
|
|
||||||
void gGraphView::SaveSettings(QString title)
|
void gGraphView::SaveSettings(QString title)
|
||||||
{
|
{
|
||||||
|
qDebug() << "Saving" << title << "settings";
|
||||||
QString filename = p_profile->Get("{DataFolder}/") + title.toLower() + ".shg";
|
QString filename = p_profile->Get("{DataFolder}/") + title.toLower() + ".shg";
|
||||||
QFile f(filename);
|
QFile f(filename);
|
||||||
f.open(QFile::WriteOnly);
|
f.open(QFile::WriteOnly);
|
||||||
|
@ -521,7 +521,7 @@ class gGraphView
|
|||||||
int strings_drawn_this_frame;
|
int strings_drawn_this_frame;
|
||||||
int strings_cached_this_frame;
|
int strings_cached_this_frame;
|
||||||
|
|
||||||
QList<SelectionHistoryItem> history;
|
QVector<SelectionHistoryItem> history;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -621,7 +621,7 @@ class gGraphView
|
|||||||
|
|
||||||
qint64 m_minx, m_maxx;
|
qint64 m_minx, m_maxx;
|
||||||
|
|
||||||
QList<SelectionHistoryItem> fwd_history;
|
QVector<SelectionHistoryItem> fwd_history;
|
||||||
float print_scaleX, print_scaleY;
|
float print_scaleX, print_scaleY;
|
||||||
|
|
||||||
QPixmap previous_day_snapshot;
|
QPixmap previous_day_snapshot;
|
||||||
|
@ -121,7 +121,7 @@ class gLineChart: public Layer
|
|||||||
QString getMetaString(qint64 time);
|
QString getMetaString(qint64 time);
|
||||||
|
|
||||||
void addDotLine(DottedLine dot) { m_dotlines.append(dot); }
|
void addDotLine(DottedLine dot) { m_dotlines.append(dot); }
|
||||||
QList<DottedLine> m_dotlines;
|
QVector<DottedLine> m_dotlines;
|
||||||
QHash<ChannelID, bool> m_flags_enabled;
|
QHash<ChannelID, bool> m_flags_enabled;
|
||||||
QHash<ChannelID, QHash<quint32, bool> > m_dot_enabled;
|
QHash<ChannelID, QHash<quint32, bool> > m_dot_enabled;
|
||||||
|
|
||||||
|
@ -162,13 +162,14 @@ void gSummaryChart::preCalc()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gSummaryChart::customCalc(Day *day, QList<SummaryChartSlice> & slices)
|
void gSummaryChart::customCalc(Day *day, QVector<SummaryChartSlice> & slices)
|
||||||
{
|
{
|
||||||
if (slices.size() != calcitems.size()) {
|
int size = slices.size();
|
||||||
|
if (size != calcitems.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float hour = day->hours(m_machtype);
|
float hour = day->hours(m_machtype);
|
||||||
for (int i=0; i<slices.size(); ++i) {
|
for (int i=0; i < size; ++i) {
|
||||||
const SummaryChartSlice & slice = slices.at(i);
|
const SummaryChartSlice & slice = slices.at(i);
|
||||||
SummaryCalcItem & calc = calcitems[i];
|
SummaryCalcItem & calc = calcitems[i];
|
||||||
|
|
||||||
@ -296,7 +297,7 @@ void gSummaryChart::afterDraw(QPainter &painter, gGraph &graph, QRect rect)
|
|||||||
|
|
||||||
QString gSummaryChart::tooltipData(Day *, int idx)
|
QString gSummaryChart::tooltipData(Day *, int idx)
|
||||||
{
|
{
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
QString txt;
|
QString txt;
|
||||||
for (int i=0; i< slices.size(); ++i) {
|
for (int i=0; i< slices.size(); ++i) {
|
||||||
SummaryChartSlice & slice = slices[i];
|
SummaryChartSlice & slice = slices[i];
|
||||||
@ -320,7 +321,7 @@ void gSummaryChart::populate(Day * day, int idx)
|
|||||||
}
|
}
|
||||||
if (!good) return;
|
if (!good) return;
|
||||||
|
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
|
|
||||||
float hours = day->hours(m_machtype);
|
float hours = day->hours(m_machtype);
|
||||||
float base = 0;
|
float base = 0;
|
||||||
@ -476,7 +477,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io
|
|||||||
|
|
||||||
day->OpenSummary();
|
day->OpenSummary();
|
||||||
|
|
||||||
QHash<int, QList<SummaryChartSlice> >::iterator cit = cache.find(i);
|
QHash<int, QVector<SummaryChartSlice> >::iterator cit = cache.find(i);
|
||||||
|
|
||||||
if (cit == cache.end()) {
|
if (cit == cache.end()) {
|
||||||
populate(day, i);
|
populate(day, i);
|
||||||
@ -484,7 +485,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cit != cache.end()) {
|
if (cit != cache.end()) {
|
||||||
QList<SummaryChartSlice> & list = cit.value();
|
QVector<SummaryChartSlice> & list = cit.value();
|
||||||
float base = 0, val;
|
float base = 0, val;
|
||||||
int listsize = list.size();
|
int listsize = list.size();
|
||||||
for (int j=0; j < listsize; ++j) {
|
for (int j=0; j < listsize; ++j) {
|
||||||
@ -549,7 +550,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io
|
|||||||
hlday = true;
|
hlday = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QList<SummaryChartSlice> >::iterator cit = cache.find(idx);
|
QHash<int, QVector<SummaryChartSlice> >::iterator cit = cache.find(idx);
|
||||||
|
|
||||||
if (cit == cache.end()) {
|
if (cit == cache.end()) {
|
||||||
populate(day, idx);
|
populate(day, idx);
|
||||||
@ -561,7 +562,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Draw pressure settings
|
/// Draw pressure settings
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
QList<SummaryChartSlice> & list = cit.value();
|
QVector<SummaryChartSlice> & list = cit.value();
|
||||||
customCalc(day, list);
|
customCalc(day, list);
|
||||||
|
|
||||||
int listsize = list.size();
|
int listsize = list.size();
|
||||||
@ -651,7 +652,7 @@ QString gUsageChart::tooltipData(Day * day, int)
|
|||||||
|
|
||||||
void gUsageChart::populate(Day *day, int idx)
|
void gUsageChart::populate(Day *day, int idx)
|
||||||
{
|
{
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
|
|
||||||
float hours = day->hours();
|
float hours = day->hours();
|
||||||
|
|
||||||
@ -675,7 +676,7 @@ void gUsageChart::preCalc()
|
|||||||
calc.reset(idx_end - idx_start);
|
calc.reset(idx_end - idx_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gUsageChart::customCalc(Day *, QList<SummaryChartSlice> &list)
|
void gUsageChart::customCalc(Day *, QVector<SummaryChartSlice> &list)
|
||||||
{
|
{
|
||||||
if (list.size() == 0) {
|
if (list.size() == 0) {
|
||||||
incompdays++;
|
incompdays++;
|
||||||
@ -738,7 +739,7 @@ void gSessionTimesChart::preCalc() {
|
|||||||
calc2.reset(idx_end - idx_start);
|
calc2.reset(idx_end - idx_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gSessionTimesChart::customCalc(Day *, QList<SummaryChartSlice> & slices) {
|
void gSessionTimesChart::customCalc(Day *, QVector<SummaryChartSlice> & slices) {
|
||||||
int size = slices.size();
|
int size = slices.size();
|
||||||
num_slices += size;
|
num_slices += size;
|
||||||
|
|
||||||
@ -867,7 +868,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion &
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QList<SummaryChartSlice> >::iterator cit = cache.find(i);
|
QHash<int, QVector<SummaryChartSlice> >::iterator cit = cache.find(i);
|
||||||
|
|
||||||
if (cit == cache.end()) {
|
if (cit == cache.end()) {
|
||||||
day->OpenSummary();
|
day->OpenSummary();
|
||||||
@ -875,7 +876,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion &
|
|||||||
splittime = QDateTime(date, split);
|
splittime = QDateTime(date, split);
|
||||||
QList<Session *>::iterator si;
|
QList<Session *>::iterator si;
|
||||||
|
|
||||||
QList<SummaryChartSlice> & slices = cache[i];
|
QVector<SummaryChartSlice> & slices = cache[i];
|
||||||
|
|
||||||
bool haveoxi = day->hasMachine(MT_OXIMETER);
|
bool haveoxi = day->hasMachine(MT_OXIMETER);
|
||||||
|
|
||||||
@ -923,7 +924,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion &
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cit != cache.end()) {
|
if (cit != cache.end()) {
|
||||||
QList<SummaryChartSlice> & list = cit.value();
|
QVector<SummaryChartSlice> & list = cit.value();
|
||||||
int listsize = list.size();
|
int listsize = list.size();
|
||||||
|
|
||||||
float peak = 0, base = 999;
|
float peak = 0, base = 999;
|
||||||
@ -981,7 +982,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion &
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QList<SummaryChartSlice> >::iterator cit = cache.find(idx);
|
QHash<int, QVector<SummaryChartSlice> >::iterator cit = cache.find(idx);
|
||||||
|
|
||||||
float x1 = lastx1 + barw;
|
float x1 = lastx1 + barw;
|
||||||
|
|
||||||
@ -995,7 +996,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion &
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cit != cache.end()) {
|
if (cit != cache.end()) {
|
||||||
QList<SummaryChartSlice> & slices = cit.value();
|
QVector<SummaryChartSlice> & slices = cit.value();
|
||||||
|
|
||||||
customCalc(day, slices);
|
customCalc(day, slices);
|
||||||
int size = slices.size();
|
int size = slices.size();
|
||||||
@ -1055,7 +1056,7 @@ void gTTIAChart::preCalc()
|
|||||||
{
|
{
|
||||||
gSummaryChart::preCalc();
|
gSummaryChart::preCalc();
|
||||||
}
|
}
|
||||||
void gTTIAChart::customCalc(Day *, QList<SummaryChartSlice> & slices)
|
void gTTIAChart::customCalc(Day *, QVector<SummaryChartSlice> & slices)
|
||||||
{
|
{
|
||||||
if (slices.size() == 0) return;
|
if (slices.size() == 0) return;
|
||||||
const SummaryChartSlice & slice = slices.at(0);
|
const SummaryChartSlice & slice = slices.at(0);
|
||||||
@ -1069,8 +1070,8 @@ void gTTIAChart::afterDraw(QPainter &, gGraph &graph, QRect rect)
|
|||||||
|
|
||||||
for (int i=0; i < num_channels; ++i) {
|
for (int i=0; i < num_channels; ++i) {
|
||||||
SummaryCalcItem & calc = calcitems[i];
|
SummaryCalcItem & calc = calcitems[i];
|
||||||
ChannelID code = calc.code;
|
//ChannelID code = calc.code;
|
||||||
schema::Channel & chan = schema::channel[code];
|
//schema::Channel & chan = schema::channel[code];
|
||||||
float mid = 0;
|
float mid = 0;
|
||||||
switch (midcalc) {
|
switch (midcalc) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -1097,7 +1098,7 @@ void gTTIAChart::afterDraw(QPainter &, gGraph &graph, QRect rect)
|
|||||||
}
|
}
|
||||||
void gTTIAChart::populate(Day *day, int idx)
|
void gTTIAChart::populate(Day *day, int idx)
|
||||||
{
|
{
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
float ttia = day->sum(CPAP_Obstructive) + day->sum(CPAP_ClearAirway) + day->sum(CPAP_Apnea) + day->sum(CPAP_Hypopnea);
|
float 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 = int(ttia) / 60 % 60;
|
int m = int(ttia) / 60 % 60;
|
||||||
@ -1108,7 +1109,7 @@ void gTTIAChart::populate(Day *day, int idx)
|
|||||||
}
|
}
|
||||||
QString gTTIAChart::tooltipData(Day *, int idx)
|
QString gTTIAChart::tooltipData(Day *, int idx)
|
||||||
{
|
{
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
if (slices.size() == 0) return QString();
|
if (slices.size() == 0) return QString();
|
||||||
|
|
||||||
const SummaryChartSlice & slice = slices.at(0);
|
const SummaryChartSlice & slice = slices.at(0);
|
||||||
@ -1132,7 +1133,7 @@ void gAHIChart::preCalc()
|
|||||||
ahi_data.clear();
|
ahi_data.clear();
|
||||||
ahi_data.reserve(idx_end-idx_start);
|
ahi_data.reserve(idx_end-idx_start);
|
||||||
}
|
}
|
||||||
void gAHIChart::customCalc(Day *day, QList<SummaryChartSlice> &list)
|
void gAHIChart::customCalc(Day *day, QVector<SummaryChartSlice> &list)
|
||||||
{
|
{
|
||||||
int size = list.size();
|
int size = list.size();
|
||||||
if (size == 0) return;
|
if (size == 0) return;
|
||||||
@ -1181,27 +1182,31 @@ void gAHIChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect rect)
|
|||||||
|
|
||||||
//int size = idx_end - idx_start;
|
//int size = idx_end - idx_start;
|
||||||
|
|
||||||
|
bool skip = true;
|
||||||
float med = 0;
|
float med = 0;
|
||||||
switch (midcalc) {
|
switch (midcalc) {
|
||||||
case 0:
|
case 0:
|
||||||
if (ahi_data.size() > 0) {
|
if (ahi_data.size() > 0) {
|
||||||
med = median(ahi_data.begin(), ahi_data.end());
|
med = median(ahi_data.begin(), ahi_data.end());
|
||||||
|
skip = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: // wavg
|
case 1: // wavg
|
||||||
if (total_hours > 0) {
|
if (total_hours > 0) {
|
||||||
med = ahi_wavg / total_hours;
|
med = ahi_wavg / total_hours;
|
||||||
|
skip = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: // avg
|
case 2: // avg
|
||||||
if (calc_cnt > 0) {
|
if (calc_cnt > 0) {
|
||||||
med = ahi_avg / calc_cnt;
|
med = ahi_avg / calc_cnt;
|
||||||
|
skip = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList txtlist;
|
QStringList txtlist;
|
||||||
txtlist.append(QObject::tr("%1 %2 / %3 / %4").arg(STR_TR_AHI).arg(min_ahi, 0, 'f', 2).arg(med, 0, 'f', 2).arg(max_ahi, 0, 'f', 2));
|
if (!skip) txtlist.append(QObject::tr("%1 %2 / %3 / %4").arg(STR_TR_AHI).arg(min_ahi, 0, 'f', 2).arg(med, 0, 'f', 2).arg(max_ahi, 0, 'f', 2));
|
||||||
|
|
||||||
int num_channels = calcitems.size();
|
int num_channels = calcitems.size();
|
||||||
|
|
||||||
@ -1210,25 +1215,29 @@ void gAHIChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect rect)
|
|||||||
ChannelID code = calc.code;
|
ChannelID code = calc.code;
|
||||||
schema::Channel & chan = schema::channel[code];
|
schema::Channel & chan = schema::channel[code];
|
||||||
float mid = 0;
|
float mid = 0;
|
||||||
|
skip = true;
|
||||||
switch (midcalc) {
|
switch (midcalc) {
|
||||||
case 0:
|
case 0:
|
||||||
if (calc.median_data.size() > 0) {
|
if (calc.median_data.size() > 0) {
|
||||||
mid = median(calc.median_data.begin(), calc.median_data.end());
|
mid = median(calc.median_data.begin(), calc.median_data.end());
|
||||||
|
skip = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (calc.divisor > 0) {
|
if (calc.divisor > 0) {
|
||||||
mid = calc.wavg_sum / calc.divisor;
|
mid = calc.wavg_sum / calc.divisor;
|
||||||
|
skip = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (calc.divisor > 0) {
|
if (calc.cnt > 0) {
|
||||||
mid = calc.avg_sum / calc.divisor;
|
mid = calc.avg_sum / calc.cnt;
|
||||||
|
skip = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
txtlist.append(QString("%1 %2 / %3 / %4").arg(chan.label()).arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2));
|
if (!skip) txtlist.append(QString("%1 %2 / %3 / %4").arg(chan.label()).arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2));
|
||||||
}
|
}
|
||||||
QString txt = txtlist.join(", ");
|
QString txt = txtlist.join(", ");
|
||||||
graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0);
|
graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0);
|
||||||
@ -1236,7 +1245,7 @@ void gAHIChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect rect)
|
|||||||
|
|
||||||
void gAHIChart::populate(Day *day, int idx)
|
void gAHIChart::populate(Day *day, int idx)
|
||||||
{
|
{
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
|
|
||||||
float hours = day->hours();
|
float hours = day->hours();
|
||||||
int num_channels = calcitems.size();
|
int num_channels = calcitems.size();
|
||||||
@ -1254,7 +1263,7 @@ void gAHIChart::populate(Day *day, int idx)
|
|||||||
}
|
}
|
||||||
QString gAHIChart::tooltipData(Day *day, int idx)
|
QString gAHIChart::tooltipData(Day *day, int idx)
|
||||||
{
|
{
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
float total = 0;
|
float total = 0;
|
||||||
float hour = day->hours(m_machtype);
|
float hour = day->hours(m_machtype);
|
||||||
QString txt;
|
QString txt;
|
||||||
@ -1290,12 +1299,76 @@ gPressureChart::gPressureChart()
|
|||||||
addCalc(CPAP_IPAP, ST_90P, brighten(schema::channel[CPAP_IPAP].defaultColor(),1.33)); // 12
|
addCalc(CPAP_IPAP, ST_90P, brighten(schema::channel[CPAP_IPAP].defaultColor(),1.33)); // 12
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRect rect)
|
||||||
|
{
|
||||||
|
int pressure_cnt = calcitems[0].cnt;
|
||||||
|
int pressuremin_cnt = calcitems[3].cnt;
|
||||||
|
int epap_cnt = calcitems[5].cnt;
|
||||||
|
int ipap_cnt = calcitems[6].cnt;
|
||||||
|
int ipaphi_cnt = calcitems[8].cnt;
|
||||||
|
int epaplo_cnt = calcitems[7].cnt;
|
||||||
|
|
||||||
|
QStringList presstr;
|
||||||
|
|
||||||
|
float mid = 0;
|
||||||
|
|
||||||
|
if (pressure_cnt > 0) {
|
||||||
|
mid = calcitems[0].mid();
|
||||||
|
presstr.append(QString("%1 %2/%3/%4").
|
||||||
|
arg(STR_TR_CPAP).
|
||||||
|
arg(calcitems[0].min,0,'f',1).
|
||||||
|
arg(mid, 0, 'f', 1).
|
||||||
|
arg(calcitems[0].max,0,'f',1));
|
||||||
|
}
|
||||||
|
if (pressuremin_cnt > 0) {
|
||||||
|
presstr.append(QString("%1 %2/%3/%4/%5").
|
||||||
|
arg(STR_TR_APAP).
|
||||||
|
arg(calcitems[3].min,0,'f',1).
|
||||||
|
arg(calcitems[1].mid(), 0, 'f', 1).
|
||||||
|
arg(calcitems[2].mid(),0,'f',1).
|
||||||
|
arg(calcitems[4].max, 0, 'f', 1));
|
||||||
|
|
||||||
|
}
|
||||||
|
if (epap_cnt > 0) {
|
||||||
|
presstr.append(QString("%1 %2/%3/%4").
|
||||||
|
arg(STR_TR_EPAP).
|
||||||
|
arg(calcitems[5].min,0,'f',1).
|
||||||
|
arg(calcitems[5].mid(), 0, 'f', 1).
|
||||||
|
arg(calcitems[5].max, 0, 'f', 1));
|
||||||
|
}
|
||||||
|
if (ipap_cnt > 0) {
|
||||||
|
presstr.append(QString("%1 %2/%3/%4").
|
||||||
|
arg(STR_TR_IPAP).
|
||||||
|
arg(calcitems[6].min,0,'f',1).
|
||||||
|
arg(calcitems[6].mid(), 0, 'f', 1).
|
||||||
|
arg(calcitems[6].max, 0, 'f', 1));
|
||||||
|
}
|
||||||
|
if (epaplo_cnt > 0) {
|
||||||
|
presstr.append(QString("%1 %2/%3/%4").
|
||||||
|
arg(STR_TR_EPAPLo).
|
||||||
|
arg(calcitems[7].min,0,'f',1).
|
||||||
|
arg(calcitems[7].mid(), 0, 'f', 1).
|
||||||
|
arg(calcitems[7].max, 0, 'f', 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipaphi_cnt > 0) {
|
||||||
|
presstr.append(QString("%1 %2/%3/%4").
|
||||||
|
arg(STR_TR_IPAPHi).
|
||||||
|
arg(calcitems[8].min,0,'f',1).
|
||||||
|
arg(calcitems[8].mid(), 0, 'f', 1).
|
||||||
|
arg(calcitems[8].max, 0, 'f', 1));
|
||||||
|
}
|
||||||
|
QString txt = presstr.join(" ");
|
||||||
|
graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void gPressureChart::populate(Day * day, int idx)
|
void gPressureChart::populate(Day * day, int idx)
|
||||||
{
|
{
|
||||||
float tmp;
|
float tmp;
|
||||||
CPAPMode mode = (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode));
|
CPAPMode mode = (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode));
|
||||||
QList<SummaryChartSlice> & slices = cache[idx];
|
QVector<SummaryChartSlice> & slices = cache[idx];
|
||||||
|
|
||||||
if (mode == MODE_CPAP) {
|
if (mode == MODE_CPAP) {
|
||||||
float pr = day->settings_max(CPAP_Pressure);
|
float pr = day->settings_max(CPAP_Pressure);
|
||||||
|
@ -58,20 +58,35 @@ struct SummaryCalcItem {
|
|||||||
SummaryCalcItem(ChannelID code, SummaryType type, QColor color)
|
SummaryCalcItem(ChannelID code, SummaryType type, QColor color)
|
||||||
:code(code), type(type), color(color) {
|
:code(code), type(type), color(color) {
|
||||||
}
|
}
|
||||||
|
float mid()
|
||||||
inline void update(float value, float weight) {
|
{
|
||||||
|
float val = 0;
|
||||||
switch (midcalc) {
|
switch (midcalc) {
|
||||||
case 0:
|
case 0:
|
||||||
median_data.append(value);
|
if (median_data.size() > 0)
|
||||||
|
val = median(median_data.begin(), median_data.end());
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
wavg_sum += value * weight;
|
if (divisor > 0)
|
||||||
divisor += weight;
|
val = wavg_sum / divisor;
|
||||||
break;
|
break;
|
||||||
default:
|
case 2:
|
||||||
|
if (cnt > 0)
|
||||||
|
val = avg_sum / cnt;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void update(float value, float weight) {
|
||||||
|
if (midcalc == 0) {
|
||||||
|
median_data.append(value);
|
||||||
|
}
|
||||||
|
|
||||||
avg_sum += value;
|
avg_sum += value;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
wavg_sum += value * weight;
|
||||||
|
divisor += weight;
|
||||||
min = qMin(min, value);
|
min = qMin(min, value);
|
||||||
max = qMax(max, value);
|
max = qMax(max, value);
|
||||||
}
|
}
|
||||||
@ -161,7 +176,7 @@ public:
|
|||||||
virtual void preCalc();
|
virtual void preCalc();
|
||||||
|
|
||||||
//! \brief Override to call stuff in main loop
|
//! \brief Override to call stuff in main loop
|
||||||
virtual void customCalc(Day *, QList<SummaryChartSlice> &);
|
virtual void customCalc(Day *, QVector<SummaryChartSlice> &);
|
||||||
|
|
||||||
//! \brief Override to call stuff after draw is complete
|
//! \brief Override to call stuff after draw is complete
|
||||||
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
||||||
@ -232,8 +247,8 @@ protected:
|
|||||||
QMap<QDate, int> dayindex;
|
QMap<QDate, int> dayindex;
|
||||||
QList<Day *> daylist;
|
QList<Day *> daylist;
|
||||||
|
|
||||||
QHash<int, QList<SummaryChartSlice> > cache;
|
QHash<int, QVector<SummaryChartSlice> > cache;
|
||||||
QList<SummaryCalcItem> calcitems;
|
QVector<SummaryCalcItem> calcitems;
|
||||||
|
|
||||||
int expected_slices;
|
int expected_slices;
|
||||||
|
|
||||||
@ -273,7 +288,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void preCalc();
|
virtual void preCalc();
|
||||||
virtual void customCalc(Day *, QList<SummaryChartSlice> & slices);
|
virtual void customCalc(Day *, QVector<SummaryChartSlice> & slices);
|
||||||
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
||||||
|
|
||||||
//! \brief Renders the graph to the QPainter object
|
//! \brief Renders the graph to the QPainter object
|
||||||
@ -309,7 +324,7 @@ public:
|
|||||||
virtual ~gUsageChart() {}
|
virtual ~gUsageChart() {}
|
||||||
|
|
||||||
virtual void preCalc();
|
virtual void preCalc();
|
||||||
virtual void customCalc(Day *, QList<SummaryChartSlice> &);
|
virtual void customCalc(Day *, QVector<SummaryChartSlice> &);
|
||||||
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
||||||
virtual void populate(Day *day, int idx);
|
virtual void populate(Day *day, int idx);
|
||||||
|
|
||||||
@ -343,7 +358,7 @@ public:
|
|||||||
virtual ~gTTIAChart() {}
|
virtual ~gTTIAChart() {}
|
||||||
|
|
||||||
virtual void preCalc();
|
virtual void preCalc();
|
||||||
virtual void customCalc(Day *, QList<SummaryChartSlice> &);
|
virtual void customCalc(Day *, QVector<SummaryChartSlice> &);
|
||||||
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
||||||
virtual void populate(Day *day, int idx);
|
virtual void populate(Day *day, int idx);
|
||||||
virtual QString tooltipData(Day * day, int);
|
virtual QString tooltipData(Day * day, int);
|
||||||
@ -376,7 +391,7 @@ public:
|
|||||||
virtual ~gAHIChart() {}
|
virtual ~gAHIChart() {}
|
||||||
|
|
||||||
virtual void preCalc();
|
virtual void preCalc();
|
||||||
virtual void customCalc(Day *, QList<SummaryChartSlice> &);
|
virtual void customCalc(Day *, QVector<SummaryChartSlice> &);
|
||||||
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
||||||
|
|
||||||
virtual void populate(Day *, int idx);
|
virtual void populate(Day *, int idx);
|
||||||
@ -426,7 +441,18 @@ public:
|
|||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual void afterDraw(QPainter &, gGraph &, QRect);
|
// virtual void preCalc();
|
||||||
|
virtual void customCalc(Day *day, QVector<SummaryChartSlice> &slices) {
|
||||||
|
int size = slices.size();
|
||||||
|
float hour = day->hours(m_machtype);
|
||||||
|
for (int i=0; i < size; ++i) {
|
||||||
|
SummaryChartSlice & slice = slices[i];
|
||||||
|
SummaryCalcItem * calc = slices[i].calc;
|
||||||
|
|
||||||
|
calc->update(slice.value, hour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void afterDraw(QPainter &, gGraph &, QRect);
|
||||||
|
|
||||||
virtual void populate(Day * day, int idx);
|
virtual void populate(Day * day, int idx);
|
||||||
|
|
||||||
|
@ -51,5 +51,6 @@
|
|||||||
<file>icons/intellipap.png</file>
|
<file>icons/intellipap.png</file>
|
||||||
<file>icons/pushpin.png</file>
|
<file>icons/pushpin.png</file>
|
||||||
<file>icons/eye.png</file>
|
<file>icons/eye.png</file>
|
||||||
|
<file>icons/prs1_60s.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "profiles.h"
|
#include "profiles.h"
|
||||||
|
|
||||||
@ -507,3 +508,114 @@ void initializeStrings()
|
|||||||
STR_TR_Avg = QObject::tr("Avg"); // Average
|
STR_TR_Avg = QObject::tr("Avg"); // Average
|
||||||
STR_TR_WAvg = QObject::tr("W-Avg"); // Weighted Average
|
STR_TR_WAvg = QObject::tr("W-Avg"); // Weighted Average
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
quint32 CRC32(const char * data, quint32 length)
|
||||||
|
{
|
||||||
|
quint32 crc32 = 0xffffffff;
|
||||||
|
|
||||||
|
for (quint32 idx=0; idx<length; idx++) {
|
||||||
|
|
||||||
|
quint32 i = (data[idx]) ^ ((crc32) & 0x000000ff);
|
||||||
|
|
||||||
|
for(int j=8; j > 0; j--) {
|
||||||
|
if (i & 1) {
|
||||||
|
i = (i >> 1) ^ 0xedb88320;
|
||||||
|
} else {
|
||||||
|
i >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crc32 = ((crc32) >> 8) ^ i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ~crc32;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 crc32buf(const QByteArray& data)
|
||||||
|
{
|
||||||
|
return CRC32(data.constData(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gzip function
|
||||||
|
QByteArray gCompress(const QByteArray& data)
|
||||||
|
{
|
||||||
|
QByteArray compressedData = qCompress(data);
|
||||||
|
// Strip the first six bytes (a 4-byte length put on by qCompress and a 2-byte zlib header)
|
||||||
|
// and the last four bytes (a zlib integrity check).
|
||||||
|
compressedData.remove(0, 6);
|
||||||
|
compressedData.chop(4);
|
||||||
|
|
||||||
|
QByteArray header;
|
||||||
|
QDataStream ds1(&header, QIODevice::WriteOnly);
|
||||||
|
// Prepend a generic 10-byte gzip header (see RFC 1952),
|
||||||
|
ds1 << quint16(0x1f8b)
|
||||||
|
<< quint16(0x0800)
|
||||||
|
<< quint16(0x0000)
|
||||||
|
<< quint16(0x0000)
|
||||||
|
<< quint16(0x000b);
|
||||||
|
|
||||||
|
// Append a four-byte CRC-32 of the uncompressed data
|
||||||
|
// Append 4 bytes uncompressed input size modulo 2^32
|
||||||
|
QByteArray footer;
|
||||||
|
QDataStream ds2(&footer, QIODevice::WriteOnly);
|
||||||
|
ds2.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
ds2 << crc32buf(data)
|
||||||
|
<< quint32(data.size());
|
||||||
|
|
||||||
|
return header + compressedData + footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Pinched from http://stackoverflow.com/questions/2690328/qt-quncompress-gzip-data
|
||||||
|
QByteArray gUncompress(const QByteArray &data)
|
||||||
|
{
|
||||||
|
if (data.size() <= 4) {
|
||||||
|
qWarning("gUncompress: Input data is truncated");
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray result;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
z_stream strm;
|
||||||
|
static const int CHUNK_SIZE = 1024;
|
||||||
|
char out[CHUNK_SIZE];
|
||||||
|
|
||||||
|
/* allocate inflate state */
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
strm.avail_in = data.size();
|
||||||
|
strm.next_in = (Bytef*)(data.data());
|
||||||
|
|
||||||
|
ret = inflateInit2(&strm, 15 + 32); // gzip decoding
|
||||||
|
if (ret != Z_OK)
|
||||||
|
return QByteArray();
|
||||||
|
|
||||||
|
// run inflate()
|
||||||
|
do {
|
||||||
|
strm.avail_out = CHUNK_SIZE;
|
||||||
|
strm.next_out = (Bytef*)(out);
|
||||||
|
|
||||||
|
ret = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case Z_NEED_DICT:
|
||||||
|
ret = Z_DATA_ERROR; // and fall through
|
||||||
|
case Z_DATA_ERROR:
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append(out, CHUNK_SIZE - strm.avail_out);
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
// clean up and return
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QByteArray gCompress(const QByteArray& data);
|
||||||
|
QByteArray gUncompress(const QByteArray &data);
|
||||||
|
|
||||||
const quint16 filetype_summary = 0;
|
const quint16 filetype_summary = 0;
|
||||||
const quint16 filetype_data = 1;
|
const quint16 filetype_data = 1;
|
||||||
const quint16 filetype_sessenabled = 5;
|
const quint16 filetype_sessenabled = 5;
|
||||||
|
@ -262,6 +262,11 @@ int CMS50Loader::doImportMode()
|
|||||||
// Either a CMS50D+, has a bad header, or it's really midnight, set a flag anyway for later to help choose the right sync time
|
// Either a CMS50D+, has a bad header, or it's really midnight, set a flag anyway for later to help choose the right sync time
|
||||||
cms50dplus = (hour == 0) && (minute == 0);
|
cms50dplus = (hour == 0) && (minute == 0);
|
||||||
|
|
||||||
|
MachineInfo info = newInfo();
|
||||||
|
info.model = cms50dplus ? QObject::tr("CMS50D+") : QObject::tr("CMS50E/F");
|
||||||
|
info.serial = QString();
|
||||||
|
Machine * mach = CreateMachine(info);
|
||||||
|
|
||||||
qDebug() << QString("Receiving Oximeter transmission %1:%2").arg(hour).arg(minute);
|
qDebug() << QString("Receiving Oximeter transmission %1:%2").arg(hour).arg(minute);
|
||||||
// set importing to true or whatever..
|
// set importing to true or whatever..
|
||||||
|
|
||||||
|
@ -121,10 +121,13 @@ struct WaveHeaderList {
|
|||||||
PRS1Loader::PRS1Loader()
|
PRS1Loader::PRS1Loader()
|
||||||
{
|
{
|
||||||
const QString PRS1_ICON = ":/icons/prs1.png";
|
const QString PRS1_ICON = ":/icons/prs1.png";
|
||||||
|
const QString PRS1_60_ICON = ":/icons/prs1_60s.png";
|
||||||
|
|
||||||
QString s = newInfo().series;
|
QString s = newInfo().series;
|
||||||
m_pixmap_paths[s] = PRS1_ICON;
|
m_pixmap_paths["System One"] = PRS1_ICON;
|
||||||
m_pixmaps[s] = QPixmap(PRS1_ICON);
|
m_pixmaps["System One"] = QPixmap(PRS1_ICON);
|
||||||
|
m_pixmap_paths["System One (60 Series)"] = PRS1_60_ICON;
|
||||||
|
m_pixmaps["System One (60 Series)"] = QPixmap(PRS1_60_ICON);
|
||||||
|
|
||||||
//genCRCTable(); // find what I did with this..
|
//genCRCTable(); // find what I did with this..
|
||||||
m_buffer = nullptr;
|
m_buffer = nullptr;
|
||||||
@ -147,6 +150,14 @@ const QString PR_STR_PSeries = "P-Series";
|
|||||||
|
|
||||||
// Tests path to see if it has (what looks like) a valid PRS1 folder structure
|
// Tests path to see if it has (what looks like) a valid PRS1 folder structure
|
||||||
bool PRS1Loader::Detect(const QString & path)
|
bool PRS1Loader::Detect(const QString & path)
|
||||||
|
{
|
||||||
|
QString newpath = checkDir(path);
|
||||||
|
|
||||||
|
return !newpath.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString PRS1Loader::checkDir(const QString & path)
|
||||||
{
|
{
|
||||||
QString newpath = path;
|
QString newpath = path;
|
||||||
|
|
||||||
@ -159,33 +170,133 @@ bool PRS1Loader::Detect(const QString & path)
|
|||||||
QDir dir(newpath);
|
QDir dir(newpath);
|
||||||
|
|
||||||
if ((!dir.exists() || !dir.isReadable())) {
|
if ((!dir.exists() || !dir.isReadable())) {
|
||||||
return false;
|
return QString();
|
||||||
}
|
}
|
||||||
qDebug() << "PRS1Loader::Detect path=" << newpath;
|
qDebug() << "PRS1Loader::Detect path=" << newpath;
|
||||||
|
|
||||||
QFile lastfile(newpath+"/last.txt");
|
QFile lastfile(newpath+"/last.txt");
|
||||||
if (!lastfile.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
QString machpath;
|
||||||
|
if (lastfile.exists()) {
|
||||||
if (!lastfile.open(QIODevice::ReadOnly)) {
|
if (!lastfile.open(QIODevice::ReadOnly)) {
|
||||||
qDebug() << "PRS1Loader: last.txt exists but I couldn't open it!";
|
qDebug() << "PRS1Loader: last.txt exists but I couldn't open it!";
|
||||||
return false;
|
} else {
|
||||||
}
|
QTextStream ts(&lastfile);
|
||||||
|
QString serial = ts.readLine(64).trimmed();
|
||||||
QString last = lastfile.readLine(64);
|
|
||||||
last = last.trimmed();
|
|
||||||
lastfile.close();
|
lastfile.close();
|
||||||
|
|
||||||
QFile f(newpath+"/"+last);
|
machpath = newpath+"/"+serial;
|
||||||
if (!f.exists()) {
|
|
||||||
qDebug() << "in PRS1Loader::Detect():" << last << "does not exist, despite last.txt saying it does";
|
if (!QDir(machpath).exists()) {
|
||||||
|
machpath = QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (machpath.isEmpty()) {
|
||||||
|
QDir dir(newpath);
|
||||||
|
QStringList dirs = dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs);
|
||||||
|
if (dirs.size() > 0) {
|
||||||
|
machpath = dirs[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return machpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseModel(MachineInfo & info, QString modelnum)
|
||||||
|
{
|
||||||
|
info.modelnumber = modelnum;
|
||||||
|
if (!modelnum.endsWith("P")) {
|
||||||
|
qDebug() << "Weird PRS1 Model number" << modelnum;
|
||||||
|
}
|
||||||
|
modelnum.chop(1);
|
||||||
|
int country = modelnum[modelnum.length() - 1].digitValue();
|
||||||
|
modelnum.chop(1);
|
||||||
|
int ser = modelnum[modelnum.length() - 1].digitValue();
|
||||||
|
modelnum.chop(1);
|
||||||
|
bool ok;
|
||||||
|
int typ = modelnum.toInt(&ok);
|
||||||
|
|
||||||
|
switch (typ) {
|
||||||
|
case 4: // cpap
|
||||||
|
info.model = QObject::tr("RemStar Plus with C-Flex+");
|
||||||
|
break;
|
||||||
|
case 5: // apap
|
||||||
|
info.model = QObject::tr("RemStar Auto with A-Flex");
|
||||||
|
break;
|
||||||
|
case 6: // bipap
|
||||||
|
info.model = QObject::tr("RemStar BiPAP Pro with Bi-Flex");
|
||||||
|
break;
|
||||||
|
case 7: // bipap auto
|
||||||
|
info.model = QObject::tr("RemStar BiPAP Auto with Bi-Flex");
|
||||||
|
break;
|
||||||
|
case 9: // asv
|
||||||
|
info.model = QObject::tr("BiPAP autoSV Advanced");
|
||||||
|
break;
|
||||||
|
case 10: // Avaps
|
||||||
|
info.model = QObject::tr("BiPAP AVAPS");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
info.model = QObject::tr("Unknown Model");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ser) {
|
||||||
|
case 5:
|
||||||
|
info.series = QObject::tr("System One");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
info.series = QObject::tr("System One (60 Series)");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
info.series = QObject::tr("unknown");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
switch (country) {
|
||||||
|
case '0':
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PRS1Loader::PeekProperties(MachineInfo & info, QString filename)
|
||||||
|
{
|
||||||
|
QFile f(filename);
|
||||||
|
if (!f.open(QFile::ReadOnly)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// newpath is a valid path
|
QTextStream in(&f);
|
||||||
|
do {
|
||||||
|
QString line = in.readLine();
|
||||||
|
QStringList pair = line.split("=");
|
||||||
|
|
||||||
|
if (pair[0].compare("ModelNumber", Qt::CaseInsensitive) == 0) {
|
||||||
|
QString modelnum = pair[1];
|
||||||
|
parseModel(info, modelnum);
|
||||||
|
}
|
||||||
|
} while (!in.atEnd());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MachineInfo PRS1Loader::PeekInfo(const QString & path)
|
||||||
|
{
|
||||||
|
QString newpath = checkDir(path);
|
||||||
|
if (newpath.isEmpty())
|
||||||
|
return MachineInfo();
|
||||||
|
|
||||||
|
MachineInfo info = newInfo();
|
||||||
|
info.serial = newpath.section("/", -1);
|
||||||
|
PeekProperties(info, newpath+"/properties.txt");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int PRS1Loader::Open(QString path)
|
int PRS1Loader::Open(QString path)
|
||||||
{
|
{
|
||||||
QString newpath;
|
QString newpath;
|
||||||
@ -216,9 +327,7 @@ int PRS1Loader::Open(QString path)
|
|||||||
QFileInfo fi = flist.at(i);
|
QFileInfo fi = flist.at(i);
|
||||||
QString filename = fi.fileName();
|
QString filename = fi.fileName();
|
||||||
|
|
||||||
if ((filename[0] == 'P') && (isdigit(filename[1])) && (isdigit(filename[2]))) {
|
if (fi.isDir() && (filename.size() > 4) && (isdigit(filename[1])) && (isdigit(filename[2]))) {
|
||||||
SerialNumbers.push_back(filename);
|
|
||||||
} else if (isdigit(filename[0]) && isdigit(filename[1])) {
|
|
||||||
SerialNumbers.push_back(filename);
|
SerialNumbers.push_back(filename);
|
||||||
} else if (filename.toLower() == "last.txt") { // last.txt points to the current serial number
|
} else if (filename.toLower() == "last.txt") { // last.txt points to the current serial number
|
||||||
QString file = fi.canonicalFilePath();
|
QString file = fi.canonicalFilePath();
|
||||||
@ -302,12 +411,12 @@ bool PRS1Loader::ParseProperties(Machine *m, QString filename)
|
|||||||
|
|
||||||
if (value == s) { continue; }
|
if (value == s) { continue; }
|
||||||
|
|
||||||
if (key.toLower() == "serialnumber") {
|
if (key.contains("serialnumber",Qt::CaseInsensitive)) {
|
||||||
info.serial = value;
|
info.serial = value;
|
||||||
} else if (key.toLower() == "modelnumber") {
|
} else if (key.contains("modelnumber",Qt::CaseInsensitive)) {
|
||||||
info.modelnumber = value;
|
parseModel(info, value);
|
||||||
} else {
|
} else {
|
||||||
if (key.toLower() == "producttype") {
|
if (key.contains("producttype", Qt::CaseInsensitive)) {
|
||||||
int i = value.toInt(&ok, 16);
|
int i = value.toInt(&ok, 16);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
@ -344,11 +453,6 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
if (!dir.exists() || (!dir.isReadable())) {
|
if (!dir.exists() || (!dir.isReadable())) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
QString backupPath = m->getBackupPath() + path.section("/", -2);
|
|
||||||
|
|
||||||
if (QDir::cleanPath(path).compare(QDir::cleanPath(backupPath)) != 0) {
|
|
||||||
copyPath(path, backupPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoSymLinks);
|
dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoSymLinks);
|
||||||
dir.setSorting(QDir::Name);
|
dir.setSorting(QDir::Name);
|
||||||
@ -360,20 +464,34 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
|
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
|
|
||||||
|
int sessionid_base = 10;
|
||||||
|
|
||||||
for (int i = 0; i < flist.size(); i++) {
|
for (int i = 0; i < flist.size(); i++) {
|
||||||
QFileInfo fi = flist.at(i);
|
QFileInfo fi = flist.at(i);
|
||||||
filename = fi.fileName();
|
filename = fi.fileName();
|
||||||
|
|
||||||
|
if (fi.isDir()) {
|
||||||
if ((filename[0].toLower() == 'p') && (isdigit(filename[1]))) {
|
if ((filename[0].toLower() == 'p') && (isdigit(filename[1]))) {
|
||||||
// p0, p1, p2.. etc.. folders contain the session data
|
// p0, p1, p2.. etc.. folders contain the session data
|
||||||
paths.push_back(fi.canonicalFilePath());
|
paths.push_back(fi.canonicalFilePath());
|
||||||
} else if ((filename.toLower() == "properties.txt") || (filename.toLower() == "prop.txt")) {
|
|
||||||
ParseProperties(m, fi.canonicalFilePath());
|
|
||||||
} else if (filename.toLower() == "e") {
|
} else if (filename.toLower() == "e") {
|
||||||
// Error files..
|
// Error files..
|
||||||
// Reminder: I have been given some info about these. should check it over.
|
// Reminder: I have been given some info about these. should check it over.
|
||||||
}
|
}
|
||||||
|
} else if (filename.compare("properties.txt",Qt::CaseInsensitive) == 0) {
|
||||||
|
ParseProperties(m, fi.canonicalFilePath());
|
||||||
|
} else if (filename.compare("PROP.TXT",Qt::CaseInsensitive) == 0) {
|
||||||
|
sessionid_base = 16;
|
||||||
|
ParseProperties(m, fi.canonicalFilePath());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString backupPath = m->getBackupPath() + path.section("/", -2);
|
||||||
|
|
||||||
|
if (QDir::cleanPath(path).compare(QDir::cleanPath(backupPath)) != 0) {
|
||||||
|
copyPath(path, backupPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QString modelstr = m->modelnumber();
|
QString modelstr = m->modelnumber();
|
||||||
|
|
||||||
@ -430,7 +548,7 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString session_s = fi.fileName().section(".", 0, -2);
|
QString session_s = fi.fileName().section(".", 0, -2);
|
||||||
sid = session_s.toInt(&ok);
|
sid = session_s.toInt(&ok, sessionid_base);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
// not a numerical session ID
|
// not a numerical session ID
|
||||||
continue;
|
continue;
|
||||||
@ -441,7 +559,7 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext == 5) {
|
if ((ext == 5) || (ext == 6)) {
|
||||||
// Waveform files aren't grouped... so we just want to add the filename for later
|
// Waveform files aren't grouped... so we just want to add the filename for later
|
||||||
QHash<SessionID, PRS1Import *>::iterator it = sesstasks.find(sid);
|
QHash<SessionID, PRS1Import *>::iterator it = sesstasks.find(sid);
|
||||||
if (it != sesstasks.end()) {
|
if (it != sesstasks.end()) {
|
||||||
@ -453,8 +571,13 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
queTask(task);
|
queTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!task->waveform.isEmpty()) continue;
|
if (ext == 5) {
|
||||||
task->waveform = fi.canonicalFilePath();
|
if (!task->wavefile.isEmpty()) continue;
|
||||||
|
task->wavefile = fi.canonicalFilePath();
|
||||||
|
} else if (ext == 6) {
|
||||||
|
if (!task->oxifile.isEmpty()) continue;
|
||||||
|
task->oxifile = fi.canonicalFilePath();
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -464,6 +587,16 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
|
|
||||||
for (int i=0; i < Chunks.size(); ++i) {
|
for (int i=0; i < Chunks.size(); ++i) {
|
||||||
PRS1DataChunk * chunk = Chunks.at(i);
|
PRS1DataChunk * chunk = Chunks.at(i);
|
||||||
|
|
||||||
|
if (ext <= 1) {
|
||||||
|
const unsigned char * data = (unsigned char *)chunk->m_data.constData();
|
||||||
|
|
||||||
|
if (data[0x00] != 0) {
|
||||||
|
delete chunk;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sid = chunk->sessionid;
|
sid = chunk->sessionid;
|
||||||
|
|
||||||
task = nullptr;
|
task = nullptr;
|
||||||
@ -500,7 +633,8 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
|
|||||||
int tasks = countTasks();
|
int tasks = countTasks();
|
||||||
runTasks(p_profile->session->multithreading());
|
runTasks(p_profile->session->multithreading());
|
||||||
finishAddingSessions();
|
finishAddingSessions();
|
||||||
return tasks;
|
|
||||||
|
return m->unsupported() ? -1 : tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PRS1Import::ParseF5Events()
|
bool PRS1Import::ParseF5Events()
|
||||||
@ -1138,7 +1272,7 @@ bool PRS1Import::ParseCompliance()
|
|||||||
session->settings[CPAP_Mode] = (int)MODE_CPAP;
|
session->settings[CPAP_Mode] = (int)MODE_CPAP;
|
||||||
|
|
||||||
EventDataType min_pressure = float(data[0x03]) / 10.0;
|
EventDataType min_pressure = float(data[0x03]) / 10.0;
|
||||||
EventDataType max_pressure = float(data[0x04]) / 10.0;
|
// EventDataType max_pressure = float(data[0x04]) / 10.0;
|
||||||
|
|
||||||
session->settings[CPAP_Pressure] = min_pressure;
|
session->settings[CPAP_Pressure] = min_pressure;
|
||||||
|
|
||||||
@ -1638,7 +1772,6 @@ bool PRS1Import::ParseSummary()
|
|||||||
session->setPhysMax(CPAP_PS, 25);
|
session->setPhysMax(CPAP_PS, 25);
|
||||||
session->setPhysMin(CPAP_PS, 0);
|
session->setPhysMin(CPAP_PS, 0);
|
||||||
|
|
||||||
|
|
||||||
switch (summary->family) {
|
switch (summary->family) {
|
||||||
case 0:
|
case 0:
|
||||||
if (summary->familyVersion == 4) {
|
if (summary->familyVersion == 4) {
|
||||||
@ -1647,7 +1780,8 @@ bool PRS1Import::ParseSummary()
|
|||||||
return ParseSummaryF0();
|
return ParseSummaryF0();
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
return ParseSummaryF3();
|
// return ParseSummaryF3();
|
||||||
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (summary->familyVersion == 0) {
|
if (summary->familyVersion == 0) {
|
||||||
return ParseSummaryF5V0();
|
return ParseSummaryF5V0();
|
||||||
@ -1656,7 +1790,12 @@ bool PRS1Import::ParseSummary()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else machine is unsupported
|
this->loader->saveMutex.lock();
|
||||||
|
if (!mach->unsupported()) {
|
||||||
|
this->loader->unsupported(mach);
|
||||||
|
}
|
||||||
|
this->loader->saveMutex.unlock();
|
||||||
|
return false;
|
||||||
|
|
||||||
const unsigned char * data = (unsigned char *)summary->m_data.constData();
|
const unsigned char * data = (unsigned char *)summary->m_data.constData();
|
||||||
|
|
||||||
@ -1865,6 +2004,50 @@ bool PRS1Import::ParseEvents()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PRS1Import::ParseOximetery()
|
||||||
|
{
|
||||||
|
int size = oximetery.size();
|
||||||
|
|
||||||
|
for (int i=0; i < size; ++i) {
|
||||||
|
PRS1DataChunk * oxi = oximetery.at(i);
|
||||||
|
int num = oxi->waveformInfo.size();
|
||||||
|
|
||||||
|
int size = oxi->m_data.size();
|
||||||
|
if (size == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
quint64 ti = quint64(oxi->timestamp) * 1000L;
|
||||||
|
qint64 dur = qint64(oxi->duration) * 1000L;
|
||||||
|
|
||||||
|
if (num > 1) {
|
||||||
|
// Process interleaved samples
|
||||||
|
QVector<QByteArray> data;
|
||||||
|
data.resize(num);
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
do {
|
||||||
|
for (int n=0; n < num; n++) {
|
||||||
|
int interleave = oxi->waveformInfo.at(n).interleave;
|
||||||
|
data[n].append(oxi->m_data.mid(pos, interleave));
|
||||||
|
pos += interleave;
|
||||||
|
}
|
||||||
|
} while (pos < size);
|
||||||
|
|
||||||
|
if (data[0].size() > 0) {
|
||||||
|
EventList * pulse = session->AddEventList(OXI_Pulse, EVL_Waveform, 1.0, 0.0, 0.0, 0.0, dur / data[0].size());
|
||||||
|
pulse->AddWaveform(ti, (unsigned char *)data[0].data(), data[0].size(), dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[1].size() > 0) {
|
||||||
|
EventList * spo2 = session->AddEventList(OXI_SPO2, EVL_Waveform, 1.0, 0.0, 0.0, 0.0, dur / data[1].size());
|
||||||
|
spo2->AddWaveform(ti, (unsigned char *)data[1].data(), data[1].size(), dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool PRS1Import::ParseWaveforms()
|
bool PRS1Import::ParseWaveforms()
|
||||||
{
|
{
|
||||||
int size = waveforms.size();
|
int size = waveforms.size();
|
||||||
@ -1915,14 +2098,19 @@ bool PRS1Import::ParseWaveforms()
|
|||||||
|
|
||||||
void PRS1Import::run()
|
void PRS1Import::run()
|
||||||
{
|
{
|
||||||
|
if (mach->unsupported())
|
||||||
|
return;
|
||||||
session = new Session(mach, sessionid);
|
session = new Session(mach, sessionid);
|
||||||
|
|
||||||
if ((compliance && ParseCompliance()) || (summary && ParseSummary())) {
|
if ((compliance && ParseCompliance()) || (summary && ParseSummary())) {
|
||||||
if (event && !ParseEvents()) {
|
if (event && !ParseEvents()) {
|
||||||
}
|
}
|
||||||
waveforms = loader->ParseFile(waveform);
|
waveforms = loader->ParseFile(wavefile);
|
||||||
ParseWaveforms();
|
ParseWaveforms();
|
||||||
|
|
||||||
|
oximetery = loader->ParseFile(oxifile);
|
||||||
|
ParseOximetery();
|
||||||
|
|
||||||
if (session->first() > 0) {
|
if (session->first() > 0) {
|
||||||
if (session->last() < session->first()) {
|
if (session->last() < session->first()) {
|
||||||
// if last isn't set, duration couldn't be gained from summary, parsing events or waveforms..
|
// if last isn't set, duration couldn't be gained from summary, parsing events or waveforms..
|
||||||
@ -2012,7 +2200,7 @@ QList<PRS1DataChunk *> PRS1Loader::ParseFile(QString path)
|
|||||||
&& (lastchunk->htype != chunk->htype)) {
|
&& (lastchunk->htype != chunk->htype)) {
|
||||||
QByteArray junk = f.read(lastblocksize - 16);
|
QByteArray junk = f.read(lastblocksize - 16);
|
||||||
|
|
||||||
|
Q_UNUSED(junk)
|
||||||
if (lastchunk->ext == 5) {
|
if (lastchunk->ext == 5) {
|
||||||
// The data is random crap
|
// The data is random crap
|
||||||
// lastchunk->m_data.append(junk.mid(lastheadersize-16));
|
// lastchunk->m_data.append(junk.mid(lastheadersize-16));
|
||||||
@ -2032,7 +2220,7 @@ QList<PRS1DataChunk *> PRS1Loader::ParseFile(QString path)
|
|||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
// Waveform Header
|
// Waveform Header
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
if (chunk->ext == 5) {
|
if ((chunk->ext == 5) || (chunk->ext == 6)) {
|
||||||
// Get extra 8 bytes in waveform header.
|
// Get extra 8 bytes in waveform header.
|
||||||
QByteArray extra = f.read(4);
|
QByteArray extra = f.read(4);
|
||||||
if (extra.size() != 4) {
|
if (extra.size() != 4) {
|
||||||
@ -2107,7 +2295,7 @@ QList<PRS1DataChunk *> PRS1Loader::ParseFile(QString path)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (chunk->ext == 5) {
|
if ((chunk->ext == 5) || (chunk->ext == 6)){
|
||||||
if (lastchunk != nullptr) {
|
if (lastchunk != nullptr) {
|
||||||
|
|
||||||
Q_ASSERT(lastchunk->sessionid == chunk->sessionid);
|
Q_ASSERT(lastchunk->sessionid == chunk->sessionid);
|
||||||
|
@ -109,13 +109,17 @@ public:
|
|||||||
PRS1DataChunk * summary;
|
PRS1DataChunk * summary;
|
||||||
PRS1DataChunk * event;
|
PRS1DataChunk * event;
|
||||||
QList<PRS1DataChunk *> waveforms;
|
QList<PRS1DataChunk *> waveforms;
|
||||||
|
QList<PRS1DataChunk *> oximetery;
|
||||||
|
|
||||||
QString waveform;
|
QString wavefile;
|
||||||
|
QString oxifile;
|
||||||
|
|
||||||
bool ParseCompliance();
|
bool ParseCompliance();
|
||||||
bool ParseSummary();
|
bool ParseSummary();
|
||||||
bool ParseEvents();
|
bool ParseEvents();
|
||||||
bool ParseWaveforms();
|
bool ParseWaveforms();
|
||||||
|
bool ParseOximetery();
|
||||||
|
|
||||||
|
|
||||||
bool ParseSummaryF0();
|
bool ParseSummaryF0();
|
||||||
bool ParseSummaryF0V4();
|
bool ParseSummaryF0V4();
|
||||||
@ -148,9 +152,15 @@ class PRS1Loader : public CPAPLoader
|
|||||||
PRS1Loader();
|
PRS1Loader();
|
||||||
virtual ~PRS1Loader();
|
virtual ~PRS1Loader();
|
||||||
|
|
||||||
|
QString checkDir(const QString & path);
|
||||||
|
bool PeekProperties(MachineInfo & info, QString path);
|
||||||
|
|
||||||
|
|
||||||
//! \brief Detect if the given path contains a valid Folder structure
|
//! \brief Detect if the given path contains a valid Folder structure
|
||||||
virtual bool Detect(const QString & path);
|
virtual bool Detect(const QString & path);
|
||||||
|
|
||||||
|
virtual MachineInfo PeekInfo(const QString & path);
|
||||||
|
|
||||||
//! \brief Scans directory path for valid PRS1 signature
|
//! \brief Scans directory path for valid PRS1 signature
|
||||||
virtual int Open(QString path);
|
virtual int Open(QString path);
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ Machine::Machine(MachineID id)
|
|||||||
{
|
{
|
||||||
day.clear();
|
day.clear();
|
||||||
highest_sessionid = 0;
|
highest_sessionid = 0;
|
||||||
|
m_unsupported = false;
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
srand(time(nullptr));
|
srand(time(nullptr));
|
||||||
@ -79,8 +80,15 @@ const quint16 sessinfo_version = 1;
|
|||||||
|
|
||||||
bool Machine::saveSessionInfo()
|
bool Machine::saveSessionInfo()
|
||||||
{
|
{
|
||||||
QFile file(getDataPath() + "Sessions.info");
|
if (info.type == MT_JOURNAL) return false;
|
||||||
file.open(QFile::WriteOnly);
|
|
||||||
|
qDebug() << "Saving" << info.brand << "session info" << info.loadername;
|
||||||
|
QString filename = getDataPath() + "Sessions.info";
|
||||||
|
QFile file(filename);
|
||||||
|
if (!file.open(QFile::WriteOnly)) {
|
||||||
|
qDebug() << "Couldn't open" << filename << "for writing";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QDataStream out(&file);
|
QDataStream out(&file);
|
||||||
out.setByteOrder(QDataStream::LittleEndian);
|
out.setByteOrder(QDataStream::LittleEndian);
|
||||||
@ -99,12 +107,19 @@ bool Machine::saveSessionInfo()
|
|||||||
Session * sess = s.value();
|
Session * sess = s.value();
|
||||||
out << (quint32) sess->session();
|
out << (quint32) sess->session();
|
||||||
out << (bool)(sess->enabled());
|
out << (bool)(sess->enabled());
|
||||||
|
|
||||||
|
//out << sess->m_availableChannels;
|
||||||
}
|
}
|
||||||
|
qDebug() << "Done Saving" << info.brand << "session info";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Machine::loadSessionInfo()
|
bool Machine::loadSessionInfo()
|
||||||
{
|
{
|
||||||
|
if (info.type == MT_JOURNAL)
|
||||||
|
return true;
|
||||||
|
|
||||||
QHash<SessionID, Session *>::iterator s;
|
QHash<SessionID, Session *>::iterator s;
|
||||||
QFile file(getDataPath() + "Sessions.info");
|
QFile file(getDataPath() + "Sessions.info");
|
||||||
if (!file.open(QFile::ReadOnly)) {
|
if (!file.open(QFile::ReadOnly)) {
|
||||||
@ -146,12 +161,20 @@ bool Machine::loadSessionInfo()
|
|||||||
for (int i=0; i< size; ++i) {
|
for (int i=0; i< size; ++i) {
|
||||||
in >> sid;
|
in >> sid;
|
||||||
in >> b;
|
in >> b;
|
||||||
|
// QList<ChannelID> avail_channels;
|
||||||
|
// if (version >= 2) {
|
||||||
|
// in >> avail_channels;
|
||||||
|
// }
|
||||||
|
|
||||||
s = sessionlist.find(sid);
|
s = sessionlist.find(sid);
|
||||||
|
|
||||||
if (s != sessionlist.end()) {
|
if (s != sessionlist.end()) {
|
||||||
Session * sess = s.value();
|
Session * sess = s.value();
|
||||||
|
|
||||||
sess->setEnabled(b);
|
sess->setEnabled(b);
|
||||||
|
// if (version >= 2) {
|
||||||
|
// sess->m_availableChannels = avail_channels;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -846,6 +869,7 @@ bool Machine::hasModifiedSessions()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QString summaryFileName = "Summaries.xml";
|
const QString summaryFileName = "Summaries.xml";
|
||||||
|
const int summaryxml_version=1;
|
||||||
|
|
||||||
bool Machine::LoadSummary(QProgressBar * progress)
|
bool Machine::LoadSummary(QProgressBar * progress)
|
||||||
{
|
{
|
||||||
@ -853,7 +877,7 @@ bool Machine::LoadSummary(QProgressBar * progress)
|
|||||||
time.start();
|
time.start();
|
||||||
qDebug() << "Loading Summaries";
|
qDebug() << "Loading Summaries";
|
||||||
|
|
||||||
QString filename = getDataPath() + summaryFileName;
|
QString filename = getDataPath() + summaryFileName + ".gz";
|
||||||
|
|
||||||
QDomDocument doc;
|
QDomDocument doc;
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
@ -866,7 +890,7 @@ bool Machine::LoadSummary(QProgressBar * progress)
|
|||||||
|
|
||||||
QByteArray data = file.readAll();
|
QByteArray data = file.readAll();
|
||||||
|
|
||||||
QByteArray uncompressed = qUncompress(data);
|
QByteArray uncompressed = gUncompress(data);
|
||||||
|
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
int errorLine;
|
int errorLine;
|
||||||
@ -879,8 +903,18 @@ bool Machine::LoadSummary(QProgressBar * progress)
|
|||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
|
|
||||||
QDomElement root = doc.documentElement();
|
QDomElement root = doc.documentElement();
|
||||||
|
|
||||||
|
if (root.tagName().compare("sessions", Qt::CaseInsensitive) != 0) {
|
||||||
|
qDebug() << "Summaries cache messed up, recreating...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
int version = root.attribute("version", "").toInt(&ok);
|
||||||
|
if (!ok || (version != summaryxml_version)) {
|
||||||
|
qDebug() << "Summaries cache outdated, recreating...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
QDomNode node;
|
QDomNode node;
|
||||||
|
|
||||||
bool s_ok;
|
bool s_ok;
|
||||||
@ -906,6 +940,37 @@ bool Machine::LoadSummary(QProgressBar * progress)
|
|||||||
sess->setEnabled(enabled);
|
sess->setEnabled(enabled);
|
||||||
sess->setSummaryOnly(!events);
|
sess->setSummaryOnly(!events);
|
||||||
|
|
||||||
|
if (e.hasChildNodes()) {
|
||||||
|
QList<ChannelID> available_channels;
|
||||||
|
QList<ChannelID> available_settings;
|
||||||
|
|
||||||
|
QDomElement chans = e.firstChildElement("channels");
|
||||||
|
if (chans.isElement()) {
|
||||||
|
QDomNode node = chans.firstChild();
|
||||||
|
QString txt = node.nodeValue();
|
||||||
|
QStringList channels = txt.split(",");
|
||||||
|
for (int i=0; i<channels.size(); ++i) {
|
||||||
|
bool ok;
|
||||||
|
ChannelID code = channels.at(i).toInt(&ok, 16);
|
||||||
|
available_channels.append(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sess->m_availableChannels = available_channels;
|
||||||
|
|
||||||
|
QDomElement sete = e.firstChildElement("settings");
|
||||||
|
if (sete.isElement()) {
|
||||||
|
QString sets = sete.firstChild().nodeValue();
|
||||||
|
QStringList settings = sets.split(",");
|
||||||
|
for (int i=0; i<settings.size(); ++i) {
|
||||||
|
bool ok;
|
||||||
|
ChannelID code = settings.at(i).toInt(&ok, 16);
|
||||||
|
available_settings.append(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sess->m_availableSettings = available_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sess_order[first] = sess;
|
sess_order[first] = sess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -935,11 +1000,9 @@ bool Machine::LoadSummary(QProgressBar * progress)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int summaryxml_version=0;
|
|
||||||
|
|
||||||
bool Machine::SaveSummary()
|
bool Machine::SaveSummary()
|
||||||
{
|
{
|
||||||
qDebug() << "Saving Summaries";
|
qDebug() << "Saving" << info.brand << info.model << "Summaries";
|
||||||
QString filename = getDataPath() + summaryFileName;
|
QString filename = getDataPath() + summaryFileName;
|
||||||
|
|
||||||
QDomDocument doc("SleepyHeadSessionIndex");
|
QDomDocument doc("SleepyHeadSessionIndex");
|
||||||
@ -967,18 +1030,49 @@ bool Machine::SaveSummary()
|
|||||||
el.setAttribute("last", sess->realLast());
|
el.setAttribute("last", sess->realLast());
|
||||||
el.setAttribute("enabled", sess->enabled() ? "1" : "0");
|
el.setAttribute("enabled", sess->enabled() ? "1" : "0");
|
||||||
el.setAttribute("events", sess->summaryOnly() ? "0" : "1");
|
el.setAttribute("events", sess->summaryOnly() ? "0" : "1");
|
||||||
|
|
||||||
|
QHash<ChannelID, QVector<EventList *> >::iterator ev;
|
||||||
|
QHash<ChannelID, QVector<EventList *> >::iterator ev_end = sess->eventlist.end();
|
||||||
|
QStringList chanlist;
|
||||||
|
for (ev = sess->eventlist.begin(); ev != ev_end; ++ev) {
|
||||||
|
chanlist.append(QString::number(ev.key(), 16));
|
||||||
|
}
|
||||||
|
if (chanlist.size() == 0) {
|
||||||
|
for (int i=0; i<sess->m_availableChannels.size(); i++) {
|
||||||
|
ChannelID code = sess->m_availableChannels.at(i);
|
||||||
|
chanlist.append(QString::number(code, 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDomElement chans = doc.createElement("channels");
|
||||||
|
chans.appendChild(doc.createTextNode(chanlist.join(",")));
|
||||||
|
el.appendChild(chans);
|
||||||
|
|
||||||
|
chanlist.clear();
|
||||||
|
QHash<ChannelID, QVariant>::iterator si;
|
||||||
|
QHash<ChannelID, QVariant>::iterator set_end = sess->settings.end();
|
||||||
|
for (si = sess->settings.begin(); si != set_end; ++si) {
|
||||||
|
chanlist.append(QString::number(si.key(), 16));
|
||||||
|
}
|
||||||
|
QDomElement settings = doc.createElement("settings");
|
||||||
|
settings.appendChild(doc.createTextNode(chanlist.join(",")));
|
||||||
|
el.appendChild(settings);
|
||||||
|
|
||||||
root.appendChild(el);
|
root.appendChild(el);
|
||||||
if (sess->IsChanged())
|
if (sess->IsChanged())
|
||||||
sess->StoreSummary();
|
sess->StoreSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile file(filename);
|
QString xmltext;
|
||||||
file.open(QIODevice::WriteOnly);
|
QTextStream ts(&xmltext);
|
||||||
|
doc.save(ts, 1);
|
||||||
|
|
||||||
QByteArray ba = qCompress(doc.toByteArray());
|
QByteArray data = gCompress(xmltext.toUtf8());
|
||||||
file.write(ba);
|
|
||||||
|
|
||||||
file.close();
|
QFile file(filename + ".gz");
|
||||||
|
|
||||||
|
file.open(QFile::WriteOnly);
|
||||||
|
file.write(data);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -173,6 +173,11 @@ class Machine
|
|||||||
QMutex listMutex;
|
QMutex listMutex;
|
||||||
QSemaphore *savelistSem;
|
QSemaphore *savelistSem;
|
||||||
|
|
||||||
|
bool m_unsupported;
|
||||||
|
|
||||||
|
bool unsupported() { return m_unsupported; }
|
||||||
|
void setUnsupported(bool b) { m_unsupported = b; }
|
||||||
|
|
||||||
void lockSaveMutex() { listMutex.lock(); }
|
void lockSaveMutex() { listMutex.lock(); }
|
||||||
void unlockSaveMutex() { listMutex.unlock(); }
|
void unlockSaveMutex() { listMutex.unlock(); }
|
||||||
void skipSaveTask() { lockSaveMutex(); m_donetasks++; unlockSaveMutex(); }
|
void skipSaveTask() { lockSaveMutex(); m_donetasks++; unlockSaveMutex(); }
|
||||||
|
@ -59,6 +59,12 @@ class MachineLoader: public QObject
|
|||||||
virtual const QString &loaderName() = 0;
|
virtual const QString &loaderName() = 0;
|
||||||
inline MachineType type() { return m_type; }
|
inline MachineType type() { return m_type; }
|
||||||
|
|
||||||
|
void unsupported(Machine * m) {
|
||||||
|
Q_ASSERT(m != nullptr);
|
||||||
|
m->setUnsupported(true);
|
||||||
|
emit machineUnsupported(m);
|
||||||
|
}
|
||||||
|
|
||||||
void queTask(ImportTask * task);
|
void queTask(ImportTask * task);
|
||||||
|
|
||||||
void addSession(Session * sess)
|
void addSession(Session * sess)
|
||||||
@ -104,6 +110,7 @@ class MachineLoader: public QObject
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateProgress(int cnt, int total);
|
void updateProgress(int cnt, int total);
|
||||||
|
void machineUnsupported(Machine *);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! \brief Contains a list of Machine records known by this loader
|
//! \brief Contains a list of Machine records known by this loader
|
||||||
|
@ -860,6 +860,7 @@ void ChannelList::add(QString group, Channel *chan)
|
|||||||
|
|
||||||
bool ChannelList::Save(QString filename)
|
bool ChannelList::Save(QString filename)
|
||||||
{
|
{
|
||||||
|
qDebug() << "Saving Channels.xml";
|
||||||
if (filename.isEmpty()) {
|
if (filename.isEmpty()) {
|
||||||
filename = p_profile->Get("{DataFolder}/") + "channels.xml";
|
filename = p_profile->Get("{DataFolder}/") + "channels.xml";
|
||||||
}
|
}
|
||||||
@ -924,6 +925,7 @@ bool ChannelList::Save(QString filename)
|
|||||||
ts << doc.toString();
|
ts << doc.toString();
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ using namespace std;
|
|||||||
|
|
||||||
// This is the uber important database version for SleepyHeads internal storage
|
// This is the uber important database version for SleepyHeads internal storage
|
||||||
// Increment this after stuffing with Session's save & load code.
|
// Increment this after stuffing with Session's save & load code.
|
||||||
const quint16 summary_version = 16;
|
const quint16 summary_version = 17;
|
||||||
const quint16 events_version = 10;
|
const quint16 events_version = 10;
|
||||||
|
|
||||||
Session::Session(Machine *m, SessionID session)
|
Session::Session(Machine *m, SessionID session)
|
||||||
@ -164,7 +164,7 @@ bool Session::Store(QString path)
|
|||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
QDataStream & operator<<(QDataStream & out, const Session & session)
|
/*QDataStream & operator<<(QDataStream & out, const Session & session)
|
||||||
{
|
{
|
||||||
session.StoreSummaryData(out);
|
session.StoreSummaryData(out);
|
||||||
return out;
|
return out;
|
||||||
@ -201,6 +201,7 @@ void Session::StoreSummaryData(QDataStream & out) const
|
|||||||
out << m_gain;
|
out << m_gain;
|
||||||
|
|
||||||
out << m_availableChannels;
|
out << m_availableChannels;
|
||||||
|
|
||||||
out << m_timeAboveTheshold;
|
out << m_timeAboveTheshold;
|
||||||
out << m_upperThreshold;
|
out << m_upperThreshold;
|
||||||
out << m_timeBelowTheshold;
|
out << m_timeBelowTheshold;
|
||||||
@ -259,7 +260,7 @@ void Session::LoadSummaryData(QDataStream & in)
|
|||||||
in >> s_summaryOnly;
|
in >> s_summaryOnly;
|
||||||
|
|
||||||
s_enabled = 1;
|
s_enabled = 1;
|
||||||
}
|
} */
|
||||||
|
|
||||||
QDataStream & operator>>(QDataStream & in, SessionSlice & slice)
|
QDataStream & operator>>(QDataStream & in, SessionSlice & slice)
|
||||||
{
|
{
|
||||||
@ -593,7 +594,14 @@ bool Session::LoadSummary()
|
|||||||
in >> s_summaryOnly;
|
in >> s_summaryOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version >= 16) {
|
if (version == 16) {
|
||||||
|
QList<SessionSlice> slices;
|
||||||
|
in >> slices;
|
||||||
|
m_slices.clear();
|
||||||
|
for (int i=0;i<slices.size(); ++i) {
|
||||||
|
m_slices.append(slices[i]);
|
||||||
|
}
|
||||||
|
} else if (version >= 17) {
|
||||||
in >> m_slices;
|
in >> m_slices;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,16 +73,16 @@ class Session
|
|||||||
//! \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();
|
bool StoreSummary();
|
||||||
|
|
||||||
//! \brief Save the Sessions Summary Indexes to the stream
|
// //! \brief Save the Sessions Summary Indexes to the stream
|
||||||
void StoreSummaryData(QDataStream & out) const;
|
// void StoreSummaryData(QDataStream & out) const;
|
||||||
|
|
||||||
//! \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();
|
bool StoreEvents();
|
||||||
|
|
||||||
//bool Load(QString path);
|
//bool Load(QString path);
|
||||||
|
|
||||||
//! \brief Loads the Sessions Summary Indexes from stream
|
// //! \brief Loads the Sessions Summary Indexes from stream
|
||||||
void LoadSummaryData(QDataStream & in);
|
// void LoadSummaryData(QDataStream & in);
|
||||||
|
|
||||||
//! \brief Loads the Sessions Summary Indexes from filename, from SleepLibs custom data format.
|
//! \brief Loads the Sessions Summary Indexes from filename, from SleepLibs custom data format.
|
||||||
bool LoadSummary();
|
bool LoadSummary();
|
||||||
@ -238,8 +238,9 @@ class Session
|
|||||||
QHash<ChannelID, EventDataType> m_timeAboveTheshold;
|
QHash<ChannelID, EventDataType> m_timeAboveTheshold;
|
||||||
|
|
||||||
QList<ChannelID> m_availableChannels;
|
QList<ChannelID> m_availableChannels;
|
||||||
|
QList<ChannelID> m_availableSettings;
|
||||||
|
|
||||||
QList<SessionSlice> m_slices;
|
QVector<SessionSlice> m_slices;
|
||||||
|
|
||||||
//! \brief Generates sum and time data for each distinct value in 'code' events..
|
//! \brief Generates sum and time data for each distinct value in 'code' events..
|
||||||
void updateCountSummary(ChannelID code);
|
void updateCountSummary(ChannelID code);
|
||||||
|
@ -184,10 +184,10 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
|
|||||||
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
|
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int oxigrp=p_profile->ExistsAndTrue("SyncOximetry") ? 0 : 1; // Contemplating killing this setting...
|
//int oxigrp=p_profile->ExistsAndTrue("SyncOximetry") ? 0 : 1; // Contemplating killing this setting...
|
||||||
for (int i=0; i < oxisize; ++i) {
|
for (int i=0; i < oxisize; ++i) {
|
||||||
ChannelID code = oxicodes[i];
|
ChannelID code = oxicodes[i];
|
||||||
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height, oxigrp);
|
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_profile->general->calculateRDI()) {
|
if (p_profile->general->calculateRDI()) {
|
||||||
@ -1123,8 +1123,8 @@ QString Daily::getCPAPInformation(Day * day)
|
|||||||
|
|
||||||
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><a class=info2 href='#'>"+info.series+" "+info.model+"<span>";
|
html+="<tr><td align=center><a class=info2 href='#'>"+info.brand + " "+ info.series+"<br/> "+info.model+"<span>";
|
||||||
QString tooltip=(info.brand+"\n"+info.series+" "+info.modelnumber+"\n"+info.serial);
|
QString tooltip=("Model "+info.modelnumber+" - "+info.serial);
|
||||||
tooltip=tooltip.replace(" "," ");
|
tooltip=tooltip.replace(" "," ");
|
||||||
|
|
||||||
html+=tooltip;
|
html+=tooltip;
|
||||||
|
BIN
sleepyhead/icons/prs1_60s.png
Normal file
BIN
sleepyhead/icons/prs1_60s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
@ -634,6 +634,11 @@ void MainWindow::Startup()
|
|||||||
// profile is a global variable set in main after login
|
// profile is a global variable set in main after login
|
||||||
p_profile->LoadMachineData();
|
p_profile->LoadMachineData();
|
||||||
|
|
||||||
|
QList<MachineLoader *> loaders = GetLoaders();
|
||||||
|
for (int i=0; i<loaders.size(); ++i) {
|
||||||
|
connect(loaders.at(i), SIGNAL(machineUnsupported(Machine*)), this, SLOT(MachineUnsupported(Machine*)));
|
||||||
|
}
|
||||||
|
|
||||||
PopulatePurgeMenu();
|
PopulatePurgeMenu();
|
||||||
|
|
||||||
// SnapshotGraph = new gGraphView(this, daily->graphView());
|
// SnapshotGraph = new gGraphView(this, daily->graphView());
|
||||||
@ -860,10 +865,16 @@ QList<ImportPath> MainWindow::detectCPAPCards()
|
|||||||
progress.setVisible(true);
|
progress.setVisible(true);
|
||||||
popup.show();
|
popup.show();
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
|
QString lastpath = (*p_profile)[STR_PREF_LastCPAPPath].toString();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Rescan in case card inserted
|
// Rescan in case card inserted
|
||||||
QStringList AutoScannerPaths = getDriveList();
|
QStringList AutoScannerPaths = getDriveList();
|
||||||
|
//AutoScannerPaths.push_back(lastpath);
|
||||||
|
|
||||||
|
if (!AutoScannerPaths.contains(lastpath)) {
|
||||||
|
AutoScannerPaths.append(lastpath);
|
||||||
|
}
|
||||||
|
|
||||||
Q_FOREACH(const QString &path, AutoScannerPaths) {
|
Q_FOREACH(const QString &path, AutoScannerPaths) {
|
||||||
// Scan through available machine loaders and test if this folder contains valid folder structure
|
// Scan through available machine loaders and test if this folder contains valid folder structure
|
||||||
@ -883,6 +894,7 @@ QList<ImportPath> MainWindow::detectCPAPCards()
|
|||||||
// needs a slight delay here
|
// needs a slight delay here
|
||||||
QThread::msleep(200);
|
QThread::msleep(200);
|
||||||
} while (detectedCards.size() == 0);
|
} while (detectedCards.size() == 0);
|
||||||
|
|
||||||
popup.hide();
|
popup.hide();
|
||||||
popup.disconnect(&skipbtn, SIGNAL(clicked()), &popup, SLOT(hide()));
|
popup.disconnect(&skipbtn, SIGNAL(clicked()), &popup, SLOT(hide()));
|
||||||
|
|
||||||
@ -934,7 +946,7 @@ void MainWindow::on_action_Import_Data_triggered()
|
|||||||
mbox.setDefaultButton(QMessageBox::Yes);
|
mbox.setDefaultButton(QMessageBox::Yes);
|
||||||
mbox.setButtonText(QMessageBox::No, tr("Specify"));
|
mbox.setButtonText(QMessageBox::No, tr("Specify"));
|
||||||
|
|
||||||
QPixmap pixmap = datacards[0].loader->getPixmap(datacards[0].loader->PeekInfo(datacards[0].path).series);
|
QPixmap pixmap = datacards[0].loader->getPixmap(datacards[0].loader->PeekInfo(datacards[0].path).series).scaled(64,64);
|
||||||
|
|
||||||
//QPixmap pixmap = QPixmap(getCPAPPixmap(datacards[0].loader->loaderName())).scaled(64,64);
|
//QPixmap pixmap = QPixmap(getCPAPPixmap(datacards[0].loader->loaderName())).scaled(64,64);
|
||||||
mbox.setIconPixmap(pixmap);
|
mbox.setIconPixmap(pixmap);
|
||||||
@ -1051,7 +1063,7 @@ void MainWindow::on_action_Import_Data_triggered()
|
|||||||
|
|
||||||
if (c >= 0) {
|
if (c >= 0) {
|
||||||
// goodlocations.push_back(dir);
|
// goodlocations.push_back(dir);
|
||||||
QDir d(dir.section("/",0,-2));
|
QDir d(dir.section("/",0,-1));
|
||||||
(*p_profile)[STR_PREF_LastCPAPPath] = d.absolutePath();
|
(*p_profile)[STR_PREF_LastCPAPPath] = d.absolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2308,6 +2320,12 @@ void MainWindow::FreeSessions()
|
|||||||
} while (date >= first);
|
} while (date >= first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::MachineUnsupported(Machine * m)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m != nullptr);
|
||||||
|
QMessageBox::information(this, STR_MessageBox_Error, QObject::tr("Sorry, your %1 %2 machine is not currently supported.").arg(m->brand()).arg(m->model()), QMessageBox::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::doReprocessEvents()
|
void MainWindow::doReprocessEvents()
|
||||||
{
|
{
|
||||||
if (p_profile->countDays(MT_CPAP, p_profile->FirstDay(), p_profile->LastDay()) == 0) {
|
if (p_profile->countDays(MT_CPAP, p_profile->FirstDay(), p_profile->LastDay()) == 0) {
|
||||||
|
@ -92,6 +92,7 @@ class MainWindow : public QMainWindow
|
|||||||
//! \brief Start the automatic update checker process
|
//! \brief Start the automatic update checker process
|
||||||
void CheckForUpdates();
|
void CheckForUpdates();
|
||||||
|
|
||||||
|
|
||||||
/*! \fn Notify(QString s,int ms=5000, QString title="SleepyHead v"+VersionString());
|
/*! \fn Notify(QString s,int ms=5000, QString title="SleepyHead v"+VersionString());
|
||||||
\brief Pops up a message box near the system tray
|
\brief Pops up a message box near the system tray
|
||||||
\param QString string
|
\param QString string
|
||||||
@ -144,6 +145,9 @@ class MainWindow : public QMainWindow
|
|||||||
//! \brief Recalculate all event summaries and flags
|
//! \brief Recalculate all event summaries and flags
|
||||||
void doReprocessEvents();
|
void doReprocessEvents();
|
||||||
|
|
||||||
|
void MachineUnsupported(Machine * m);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void closeEvent(QCloseEvent *);
|
virtual void closeEvent(QCloseEvent *);
|
||||||
virtual void keyPressEvent(QKeyEvent *event);
|
virtual void keyPressEvent(QKeyEvent *event);
|
||||||
|
@ -3132,12 +3132,20 @@ border-radius: 10px;
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&File</string>
|
<string>&File</string>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QMenu" name="menuExp_ort_CSV_Data">
|
||||||
|
<property name="title">
|
||||||
|
<string>Exp&ort Data</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionExport_CSV"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionExport_Current_Day"/>
|
||||||
|
</widget>
|
||||||
<addaction name="action_Import_Data"/>
|
<addaction name="action_Import_Data"/>
|
||||||
<addaction name="action_Preferences"/>
|
<addaction name="action_Preferences"/>
|
||||||
<addaction name="action_Edit_Profile"/>
|
<addaction name="action_Edit_Profile"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionPrint_Report"/>
|
<addaction name="actionPrint_Report"/>
|
||||||
<addaction name="actionExp_ort"/>
|
<addaction name="menuExp_ort_CSV_Data"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExport_Journal"/>
|
<addaction name="actionExport_Journal"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@ -3366,11 +3374,6 @@ border-radius: 10px;
|
|||||||
<string>&Edit Profile</string>
|
<string>&Edit Profile</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionExp_ort">
|
|
||||||
<property name="text">
|
|
||||||
<string>Exp&ort Data</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionOnline_Users_Guide">
|
<action name="actionOnline_Users_Guide">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Online Users &Guide</string>
|
<string>Online Users &Guide</string>
|
||||||
@ -3521,6 +3524,16 @@ border-radius: 10px;
|
|||||||
<string>Show Performance Information</string>
|
<string>Show Performance Information</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionExport_CSV">
|
||||||
|
<property name="text">
|
||||||
|
<string>Export as CSV</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport_Current_Day">
|
||||||
|
<property name="text">
|
||||||
|
<string>Export for Review</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
@ -993,6 +993,7 @@ void OximeterImport::on_saveButton_clicked()
|
|||||||
mach->AddSession(session);
|
mach->AddSession(session);
|
||||||
mach->Save();
|
mach->Save();
|
||||||
mach->SaveSummary();
|
mach->SaveSummary();
|
||||||
|
p_profile->StoreMachines();
|
||||||
|
|
||||||
mainwin->getDaily()->LoadDate(mainwin->getDaily()->getDate());
|
mainwin->getDaily()->LoadDate(mainwin->getDaily()->getDate());
|
||||||
mainwin->getOverview()->ReloadGraphs();
|
mainwin->getOverview()->ReloadGraphs();
|
||||||
|
@ -48,7 +48,7 @@ SessionBar::SessionBar(QWidget *parent) :
|
|||||||
// :QWidget(this)
|
// :QWidget(this)
|
||||||
//{
|
//{
|
||||||
// timer.setParent(this);
|
// timer.setParent(this);
|
||||||
// QList<SBSeg>::const_iterator i;
|
// QVector<SBSeg>::const_iterator i;
|
||||||
// for (i=copy.segments.begin();i!=copy.segments.end();++i) {
|
// for (i=copy.segments.begin();i!=copy.segments.end();++i) {
|
||||||
// segments.push_back(*i);
|
// segments.push_back(*i);
|
||||||
// }
|
// }
|
||||||
@ -60,7 +60,7 @@ SessionBar::~SessionBar()
|
|||||||
void SessionBar::updateTimer()
|
void SessionBar::updateTimer()
|
||||||
{
|
{
|
||||||
if (!underMouse()) {
|
if (!underMouse()) {
|
||||||
QList<SBSeg>::iterator i;
|
QVector<SBSeg>::iterator i;
|
||||||
|
|
||||||
for (i = segments.begin(); i != segments.end(); ++i) {
|
for (i = segments.begin(); i != segments.end(); ++i) {
|
||||||
(*i).highlight = false;
|
(*i).highlight = false;
|
||||||
@ -78,7 +78,7 @@ SegType SessionBar::min()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<SBSeg>::iterator i = segments.begin();
|
QVector<SBSeg>::iterator i = segments.begin();
|
||||||
SegType min = (*i).session->first();
|
SegType min = (*i).session->first();
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ SegType SessionBar::max()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<SBSeg>::iterator i = segments.begin();
|
QVector<SBSeg>::iterator i = segments.begin();
|
||||||
SegType max = (*i).session->last();
|
SegType max = (*i).session->last();
|
||||||
i++;
|
i++;
|
||||||
qint64 val;
|
qint64 val;
|
||||||
@ -132,7 +132,7 @@ void SessionBar::mousePressEvent(QMouseEvent *ev)
|
|||||||
double px = double(width() ) / double(total);
|
double px = double(width() ) / double(total);
|
||||||
|
|
||||||
double sx, ex;
|
double sx, ex;
|
||||||
QList<SBSeg>::iterator i;
|
QVector<SBSeg>::iterator i;
|
||||||
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ void SessionBar::mouseMoveEvent(QMouseEvent *ev)
|
|||||||
double px = double(width() - 5) / double(total);
|
double px = double(width() - 5) / double(total);
|
||||||
|
|
||||||
double sx, ex;
|
double sx, ex;
|
||||||
QList<SBSeg>::iterator i;
|
QVector<SBSeg>::iterator i;
|
||||||
|
|
||||||
for (i = segments.begin(); i != segments.end(); ++i) {
|
for (i = segments.begin(); i != segments.end(); ++i) {
|
||||||
SBSeg &seg = *i;
|
SBSeg &seg = *i;
|
||||||
@ -216,7 +216,7 @@ void SessionBar::paintEvent(QPaintEvent *)
|
|||||||
double px = double(width() - 5) / double(total);
|
double px = double(width() - 5) / double(total);
|
||||||
|
|
||||||
double sx, ex;
|
double sx, ex;
|
||||||
QList<SBSeg>::iterator i;
|
QVector<SBSeg>::iterator i;
|
||||||
QRect selectRect;
|
QRect selectRect;
|
||||||
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#ifndef SESSIONBAR_H
|
#ifndef SESSIONBAR_H
|
||||||
#define SESSIONBAR_H
|
#define SESSIONBAR_H
|
||||||
|
|
||||||
#include <QList>
|
#include <QVector>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@ -60,7 +60,7 @@ class SessionBar : public QWidget
|
|||||||
SegType min();
|
SegType min();
|
||||||
SegType max();
|
SegType max();
|
||||||
|
|
||||||
QList<SBSeg> segments;
|
QVector<SBSeg> segments;
|
||||||
QTimer timer;
|
QTimer timer;
|
||||||
int m_selectIDX;
|
int m_selectIDX;
|
||||||
bool m_selectMode;
|
bool m_selectMode;
|
||||||
|
@ -76,6 +76,7 @@ QDataStream & operator<<(QDataStream & out, const RXItem & rx)
|
|||||||
|
|
||||||
out << rx.machine->loaderName();
|
out << rx.machine->loaderName();
|
||||||
out << rx.machine->serial();
|
out << rx.machine->serial();
|
||||||
|
|
||||||
out << rx.relief;
|
out << rx.relief;
|
||||||
out << rx.mode;
|
out << rx.mode;
|
||||||
out << rx.pressure;
|
out << rx.pressure;
|
||||||
|
Loading…
Reference in New Issue
Block a user