From cfca3781605cb6f40a2cf4da866508edf90f03c6 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 14:12:16 -0400
Subject: [PATCH 01/13] Move pressure chart class into its own files.

---
 oscar/Graphs/gPressureChart.cpp     | 200 ++++++++++++++++++++++++++++
 oscar/Graphs/gPressureChart.h       |  48 +++++++
 oscar/Graphs/gSessionTimesChart.cpp | 197 +--------------------------
 oscar/Graphs/gSessionTimesChart.h   |  36 +----
 oscar/oscar.pro                     |   2 +
 oscar/overview.cpp                  |   4 +-
 6 files changed, 256 insertions(+), 231 deletions(-)
 create mode 100644 oscar/Graphs/gPressureChart.cpp
 create mode 100644 oscar/Graphs/gPressureChart.h

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
new file mode 100644
index 00000000..b494a2af
--- /dev/null
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -0,0 +1,200 @@
+/* gPressureChart Implementation
+ *
+ * Copyright (c) 2020 The Oscar Team
+ * Copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of the source code
+ * for more details. */
+
+#include "gPressureChart.h"
+
+gPressureChart::gPressureChart()
+    : gSummaryChart("Pressure", MT_CPAP)
+{
+
+    // Do not reorder these!!! :P
+    addCalc(CPAP_Pressure, ST_SETMAX, schema::channel[CPAP_Pressure].defaultColor());    // 00
+    addCalc(CPAP_Pressure, ST_MID, schema::channel[CPAP_Pressure].defaultColor());       // 01
+    addCalc(CPAP_Pressure, ST_90P, brighten(schema::channel[CPAP_Pressure].defaultColor(), 1.33f)); // 02
+    addCalc(CPAP_PressureMin, ST_SETMIN, schema::channel[CPAP_PressureMin].defaultColor());  // 03
+    addCalc(CPAP_PressureMax, ST_SETMAX, schema::channel[CPAP_PressureMax].defaultColor());  // 04
+
+    addCalc(CPAP_EPAP, ST_SETMAX, schema::channel[CPAP_EPAP].defaultColor());      // 05
+    addCalc(CPAP_IPAP, ST_SETMAX, schema::channel[CPAP_IPAP].defaultColor());      // 06
+    addCalc(CPAP_EPAPLo, ST_SETMAX, schema::channel[CPAP_EPAPLo].defaultColor());    // 07
+    addCalc(CPAP_IPAPHi, ST_SETMAX, schema::channel[CPAP_IPAPHi].defaultColor());    // 08
+
+    addCalc(CPAP_EPAP, ST_MID, schema::channel[CPAP_EPAP].defaultColor());         // 09
+    addCalc(CPAP_EPAP, ST_90P, brighten(schema::channel[CPAP_EPAP].defaultColor(),1.33f));         // 10
+    addCalc(CPAP_IPAP, ST_MID, schema::channel[CPAP_IPAP].defaultColor());         // 11
+    addCalc(CPAP_IPAP, ST_90P, brighten(schema::channel[CPAP_IPAP].defaultColor(),1.33f));         // 12
+}
+
+void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF 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)
+{
+    float tmp;
+    CPAPMode mode =  (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode));
+    QVector<SummaryChartSlice> & slices = cache[idx];
+
+    if (mode == MODE_CPAP) {
+        float pr = day->settings_max(CPAP_Pressure);
+        slices.append(SummaryChartSlice(&calcitems[0], pr, pr, schema::channel[CPAP_Pressure].label(), calcitems[0].color));
+    } else if (mode == MODE_APAP) {
+        float min = day->settings_min(CPAP_PressureMin);
+        float max = day->settings_max(CPAP_PressureMax);
+
+        tmp = min;
+
+        slices.append(SummaryChartSlice(&calcitems[3], min, min, schema::channel[CPAP_PressureMin].label(), calcitems[3].color));
+        if (!day->summaryOnly()) {
+            float med = day->calcMiddle(CPAP_Pressure);
+            slices.append(SummaryChartSlice(&calcitems[1], med, med - tmp, day->calcMiddleLabel(CPAP_Pressure), calcitems[1].color));
+            tmp += med - tmp;
+
+            float p90 = day->calcPercentile(CPAP_Pressure);
+            slices.append(SummaryChartSlice(&calcitems[2], p90, p90 - tmp, day->calcPercentileLabel(CPAP_Pressure), calcitems[2].color));
+            tmp += p90 - tmp;
+        }
+        slices.append(SummaryChartSlice(&calcitems[4], max, max - tmp, schema::channel[CPAP_PressureMax].label(), calcitems[4].color));
+
+    } else if (mode == MODE_BILEVEL_FIXED) {
+        float epap = day->settings_max(CPAP_EPAP);
+        float ipap = day->settings_max(CPAP_IPAP);
+
+        slices.append(SummaryChartSlice(&calcitems[5], epap, epap, schema::channel[CPAP_EPAP].label(), calcitems[5].color));
+        slices.append(SummaryChartSlice(&calcitems[6], ipap, ipap - epap, schema::channel[CPAP_IPAP].label(), calcitems[6].color));
+
+    } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
+        float epap = day->settings_max(CPAP_EPAPLo);
+        tmp = epap;
+        float ipap = day->settings_max(CPAP_IPAPHi);
+
+        slices.append(SummaryChartSlice(&calcitems[7], epap, epap, schema::channel[CPAP_EPAPLo].label(), calcitems[7].color));
+        if (!day->summaryOnly()) {
+
+            float e50 = day->calcMiddle(CPAP_EPAP);
+            slices.append(SummaryChartSlice(&calcitems[9], e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), calcitems[9].color));
+            tmp += e50 - tmp;
+
+            float e90 = day->calcPercentile(CPAP_EPAP);
+            slices.append(SummaryChartSlice(&calcitems[10], e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), calcitems[10].color));
+            tmp += e90 - tmp;
+
+            float i50 = day->calcMiddle(CPAP_IPAP);
+            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
+            tmp += i50 - tmp;
+
+            float i90 = day->calcPercentile(CPAP_IPAP);
+            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
+            tmp += i90 - tmp;
+        }
+        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
+    } else if ((mode == MODE_BILEVEL_AUTO_VARIABLE_PS) || (mode == MODE_ASV_VARIABLE_EPAP)) {
+        float epap = day->settings_max(CPAP_EPAPLo);
+        tmp = epap;
+
+        slices.append(SummaryChartSlice(&calcitems[7], epap, epap, schema::channel[CPAP_EPAPLo].label(), calcitems[7].color));
+        if (!day->summaryOnly()) {
+            float e50 = day->calcMiddle(CPAP_EPAP);
+            slices.append(SummaryChartSlice(&calcitems[9], e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), calcitems[9].color));
+            tmp += e50 - tmp;
+
+            float e90 = day->calcPercentile(CPAP_EPAP);
+            slices.append(SummaryChartSlice(&calcitems[10], e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), calcitems[10].color));
+            tmp += e90 - tmp;
+
+            float i50 = day->calcMiddle(CPAP_IPAP);
+            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
+            tmp += i50 - tmp;
+
+            float i90 = day->calcPercentile(CPAP_IPAP);
+            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
+            tmp += i90 - tmp;
+        }
+        float ipap = day->settings_max(CPAP_IPAPHi);
+        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
+    } else if (mode == MODE_ASV) {
+        float epap = day->settings_max(CPAP_EPAP);
+        tmp = epap;
+
+        slices.append(SummaryChartSlice(&calcitems[5], epap, epap, schema::channel[CPAP_EPAP].label(), calcitems[5].color));
+        if (!day->summaryOnly()) {
+            float i50 = day->calcMiddle(CPAP_IPAP);
+            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
+            tmp += i50 - tmp;
+
+            float i90 = day->calcPercentile(CPAP_IPAP);
+            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
+            tmp += i90 - tmp;
+        }
+        float ipap = day->settings_max(CPAP_IPAPHi);
+        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
+    }
+
+}
diff --git a/oscar/Graphs/gPressureChart.h b/oscar/Graphs/gPressureChart.h
new file mode 100644
index 00000000..fbfb9822
--- /dev/null
+++ b/oscar/Graphs/gPressureChart.h
@@ -0,0 +1,48 @@
+/* gPressureChart Header
+ *
+ * Copyright (c) 2020 The Oscar Team
+ * Copyright (C) 2011-2018 Mark Watkins <mark@jedimark.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of the source code
+ * for more details. */
+
+#ifndef GPRESSURECHART_H
+#define GPRESSURECHART_H
+
+#include "gSessionTimesChart.h"
+
+class gPressureChart : public gSummaryChart
+{
+public:
+    gPressureChart();
+    virtual ~gPressureChart() {}
+
+    virtual Layer * Clone() {
+        gPressureChart * sc = new gPressureChart();
+        gSummaryChart::CloneInto(sc);
+        return sc;
+    }
+
+//    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 &, QRectF);
+
+    virtual void populate(Day * day, int idx);
+
+    virtual QString tooltipData(Day * day, int idx) {
+        return day->getCPAPModeStr() + "\n" + day->getPressureSettings() + gSummaryChart::tooltipData(day, idx);
+    }
+
+};
+
+#endif // GPRESSURECHART_H
diff --git a/oscar/Graphs/gSessionTimesChart.cpp b/oscar/Graphs/gSessionTimesChart.cpp
index b64373a2..7e380852 100644
--- a/oscar/Graphs/gSessionTimesChart.cpp
+++ b/oscar/Graphs/gSessionTimesChart.cpp
@@ -1,5 +1,6 @@
 /* gSessionTimesChart Implementation
  *
+ * Copyright (c) 2020 The Oscar Team
  * Copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net>
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -1288,199 +1289,3 @@ QString gAHIChart::tooltipData(Day *day, int idx)
     }
     return QString("\n%1: %2").arg(STR_TR_AHI).arg(float(total) / hour,0,'f',2)+txt;
 }
-
-
-gPressureChart::gPressureChart()
-    :gSummaryChart("Pressure", MT_CPAP)
-{
-
-    // Do not reorder these!!! :P
-    addCalc(CPAP_Pressure, ST_SETMAX, schema::channel[CPAP_Pressure].defaultColor());    // 00
-    addCalc(CPAP_Pressure, ST_MID, schema::channel[CPAP_Pressure].defaultColor());       // 01
-    addCalc(CPAP_Pressure, ST_90P, brighten(schema::channel[CPAP_Pressure].defaultColor(), 1.33f)); // 02
-    addCalc(CPAP_PressureMin, ST_SETMIN, schema::channel[CPAP_PressureMin].defaultColor());  // 03
-    addCalc(CPAP_PressureMax, ST_SETMAX, schema::channel[CPAP_PressureMax].defaultColor());  // 04
-
-    addCalc(CPAP_EPAP, ST_SETMAX, schema::channel[CPAP_EPAP].defaultColor());      // 05
-    addCalc(CPAP_IPAP, ST_SETMAX, schema::channel[CPAP_IPAP].defaultColor());      // 06
-    addCalc(CPAP_EPAPLo, ST_SETMAX, schema::channel[CPAP_EPAPLo].defaultColor());    // 07
-    addCalc(CPAP_IPAPHi, ST_SETMAX, schema::channel[CPAP_IPAPHi].defaultColor());    // 08
-
-    addCalc(CPAP_EPAP, ST_MID, schema::channel[CPAP_EPAP].defaultColor());         // 09
-    addCalc(CPAP_EPAP, ST_90P, brighten(schema::channel[CPAP_EPAP].defaultColor(),1.33f));         // 10
-    addCalc(CPAP_IPAP, ST_MID, schema::channel[CPAP_IPAP].defaultColor());         // 11
-    addCalc(CPAP_IPAP, ST_90P, brighten(schema::channel[CPAP_IPAP].defaultColor(),1.33f));         // 12
-}
-
-void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF 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)
-{
-    float tmp;
-    CPAPMode mode =  (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode));
-    QVector<SummaryChartSlice> & slices = cache[idx];
-
-    if (mode == MODE_CPAP) {
-        float pr = day->settings_max(CPAP_Pressure);
-        slices.append(SummaryChartSlice(&calcitems[0], pr, pr, schema::channel[CPAP_Pressure].label(), calcitems[0].color));
-    } else if (mode == MODE_APAP) {
-        float min = day->settings_min(CPAP_PressureMin);
-        float max = day->settings_max(CPAP_PressureMax);
-
-        tmp = min;
-
-        slices.append(SummaryChartSlice(&calcitems[3], min, min, schema::channel[CPAP_PressureMin].label(), calcitems[3].color));
-        if (!day->summaryOnly()) {
-            float med = day->calcMiddle(CPAP_Pressure);
-            slices.append(SummaryChartSlice(&calcitems[1], med, med - tmp, day->calcMiddleLabel(CPAP_Pressure), calcitems[1].color));
-            tmp += med - tmp;
-
-            float p90 = day->calcPercentile(CPAP_Pressure);
-            slices.append(SummaryChartSlice(&calcitems[2], p90, p90 - tmp, day->calcPercentileLabel(CPAP_Pressure), calcitems[2].color));
-            tmp += p90 - tmp;
-        }
-        slices.append(SummaryChartSlice(&calcitems[4], max, max - tmp, schema::channel[CPAP_PressureMax].label(), calcitems[4].color));
-
-    } else if (mode == MODE_BILEVEL_FIXED) {
-        float epap = day->settings_max(CPAP_EPAP);
-        float ipap = day->settings_max(CPAP_IPAP);
-
-        slices.append(SummaryChartSlice(&calcitems[5], epap, epap, schema::channel[CPAP_EPAP].label(), calcitems[5].color));
-        slices.append(SummaryChartSlice(&calcitems[6], ipap, ipap - epap, schema::channel[CPAP_IPAP].label(), calcitems[6].color));
-
-    } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
-        float epap = day->settings_max(CPAP_EPAPLo);
-        tmp = epap;
-        float ipap = day->settings_max(CPAP_IPAPHi);
-
-        slices.append(SummaryChartSlice(&calcitems[7], epap, epap, schema::channel[CPAP_EPAPLo].label(), calcitems[7].color));
-        if (!day->summaryOnly()) {
-
-            float e50 = day->calcMiddle(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[9], e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), calcitems[9].color));
-            tmp += e50 - tmp;
-
-            float e90 = day->calcPercentile(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[10], e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), calcitems[10].color));
-            tmp += e90 - tmp;
-
-            float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
-            tmp += i50 - tmp;
-
-            float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
-            tmp += i90 - tmp;
-        }
-        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
-    } else if ((mode == MODE_BILEVEL_AUTO_VARIABLE_PS) || (mode == MODE_ASV_VARIABLE_EPAP)) {
-        float epap = day->settings_max(CPAP_EPAPLo);
-        tmp = epap;
-
-        slices.append(SummaryChartSlice(&calcitems[7], epap, epap, schema::channel[CPAP_EPAPLo].label(), calcitems[7].color));
-        if (!day->summaryOnly()) {
-            float e50 = day->calcMiddle(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[9], e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), calcitems[9].color));
-            tmp += e50 - tmp;
-
-            float e90 = day->calcPercentile(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[10], e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), calcitems[10].color));
-            tmp += e90 - tmp;
-
-            float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
-            tmp += i50 - tmp;
-
-            float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
-            tmp += i90 - tmp;
-        }
-        float ipap = day->settings_max(CPAP_IPAPHi);
-        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
-    } else if (mode == MODE_ASV) {
-        float epap = day->settings_max(CPAP_EPAP);
-        tmp = epap;
-
-        slices.append(SummaryChartSlice(&calcitems[5], epap, epap, schema::channel[CPAP_EPAP].label(), calcitems[5].color));
-        if (!day->summaryOnly()) {
-            float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
-            tmp += i50 - tmp;
-
-            float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
-            tmp += i90 - tmp;
-        }
-        float ipap = day->settings_max(CPAP_IPAPHi);
-        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
-    }
-
-}
-
-//void gPressureChart::afterDraw(QPainter &painter, gGraph &graph, QRect rect)
-//{
-//}
-
diff --git a/oscar/Graphs/gSessionTimesChart.h b/oscar/Graphs/gSessionTimesChart.h
index 5e56c0d0..87988313 100644
--- a/oscar/Graphs/gSessionTimesChart.h
+++ b/oscar/Graphs/gSessionTimesChart.h
@@ -1,5 +1,6 @@
-/* gSessionTimesChart Header
+/* gSessionTimesChart Header
  *
+ * Copyright (c) 2020 The Oscar Team
  * Copyright (C) 2011-2018 Mark Watkins <mark@jedimark.net>
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -429,37 +430,4 @@ public:
 };
 
 
-class gPressureChart : public gSummaryChart
-{
-public:
-    gPressureChart();
-    virtual ~gPressureChart() {}
-
-    virtual Layer * Clone() {
-        gPressureChart * sc = new gPressureChart();
-        gSummaryChart::CloneInto(sc);
-        return sc;
-    }
-
-//    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 &, QRectF);
-
-    virtual void populate(Day * day, int idx);
-
-    virtual QString tooltipData(Day * day, int idx) {
-        return day->getCPAPModeStr() + "\n" + day->getPressureSettings() + gSummaryChart::tooltipData(day, idx);
-    }
-
-};
-
 #endif // GSESSIONTIMESCHART_H
diff --git a/oscar/oscar.pro b/oscar/oscar.pro
index a021d135..be134f98 100644
--- a/oscar/oscar.pro
+++ b/oscar/oscar.pro
@@ -305,6 +305,7 @@ SOURCES += \
     SleepLib/serialoximeter.cpp \
     SleepLib/loader_plugins/md300w1_loader.cpp \
     Graphs/gSessionTimesChart.cpp \
+    Graphs/gPressureChart.cpp \
     logger.cpp \
     SleepLib/machine_common.cpp \
     SleepLib/loader_plugins/weinmann_loader.cpp \
@@ -383,6 +384,7 @@ HEADERS  += \
     SleepLib/serialoximeter.h \
     SleepLib/loader_plugins/md300w1_loader.h \
     Graphs/gSessionTimesChart.h \
+    Graphs/gPressureChart.h \
     logger.h \
     SleepLib/loader_plugins/weinmann_loader.h \
     Graphs/gdailysummary.h \
diff --git a/oscar/overview.cpp b/oscar/overview.cpp
index 9cc986a0..9dc2d8e9 100644
--- a/oscar/overview.cpp
+++ b/oscar/overview.cpp
@@ -1,5 +1,6 @@
-/* Overview GUI Implementation
+/* Overview GUI Implementation
  *
+ * Copyright (c) 2020 The Oscar Team
  * Copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net>
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -23,6 +24,7 @@
 #include "Graphs/gXAxis.h"
 #include "Graphs/gLineChart.h"
 #include "Graphs/gYAxis.h"
+#include "Graphs/gPressureChart.h"
 #include "cprogressbar.h"
 
 #include "mainwindow.h"

From 0ebf4e70a36a374cebab591101cb2176303f4c56 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 14:46:49 -0400
Subject: [PATCH 02/13] Clean up gPressureChart constructor, with minor
 refactoring.

---
 oscar/Graphs/gPressureChart.cpp     | 35 ++++++++++++++++++-----------
 oscar/Graphs/gPressureChart.h       |  1 +
 oscar/Graphs/gSessionTimesChart.cpp | 11 +++++++++
 oscar/Graphs/gSessionTimesChart.h   |  9 ++------
 4 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index b494a2af..cac04bfa 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -14,21 +14,30 @@ gPressureChart::gPressureChart()
 {
 
     // Do not reorder these!!! :P
-    addCalc(CPAP_Pressure, ST_SETMAX, schema::channel[CPAP_Pressure].defaultColor());    // 00
-    addCalc(CPAP_Pressure, ST_MID, schema::channel[CPAP_Pressure].defaultColor());       // 01
-    addCalc(CPAP_Pressure, ST_90P, brighten(schema::channel[CPAP_Pressure].defaultColor(), 1.33f)); // 02
-    addCalc(CPAP_PressureMin, ST_SETMIN, schema::channel[CPAP_PressureMin].defaultColor());  // 03
-    addCalc(CPAP_PressureMax, ST_SETMAX, schema::channel[CPAP_PressureMax].defaultColor());  // 04
+    addCalc(CPAP_Pressure, ST_SETMAX);     // 00
+    addCalc(CPAP_Pressure, ST_MID);        // 01
+    addCalc(CPAP_Pressure, ST_90P);        // 02
+    addCalc(CPAP_PressureMin, ST_SETMIN);  // 03
+    addCalc(CPAP_PressureMax, ST_SETMAX);  // 04
 
-    addCalc(CPAP_EPAP, ST_SETMAX, schema::channel[CPAP_EPAP].defaultColor());      // 05
-    addCalc(CPAP_IPAP, ST_SETMAX, schema::channel[CPAP_IPAP].defaultColor());      // 06
-    addCalc(CPAP_EPAPLo, ST_SETMAX, schema::channel[CPAP_EPAPLo].defaultColor());    // 07
-    addCalc(CPAP_IPAPHi, ST_SETMAX, schema::channel[CPAP_IPAPHi].defaultColor());    // 08
+    addCalc(CPAP_EPAP, ST_SETMAX);      // 05
+    addCalc(CPAP_IPAP, ST_SETMAX);      // 06
+    addCalc(CPAP_EPAPLo, ST_SETMAX);    // 07
+    addCalc(CPAP_IPAPHi, ST_SETMAX);    // 08
 
-    addCalc(CPAP_EPAP, ST_MID, schema::channel[CPAP_EPAP].defaultColor());         // 09
-    addCalc(CPAP_EPAP, ST_90P, brighten(schema::channel[CPAP_EPAP].defaultColor(),1.33f));         // 10
-    addCalc(CPAP_IPAP, ST_MID, schema::channel[CPAP_IPAP].defaultColor());         // 11
-    addCalc(CPAP_IPAP, ST_90P, brighten(schema::channel[CPAP_IPAP].defaultColor(),1.33f));         // 12
+    addCalc(CPAP_EPAP, ST_MID);         // 09
+    addCalc(CPAP_EPAP, ST_90P);         // 10
+    addCalc(CPAP_IPAP, ST_MID);         // 11
+    addCalc(CPAP_IPAP, ST_90P);         // 12
+}
+
+int gPressureChart::addCalc(ChannelID code, SummaryType type) {
+    QColor color = schema::channel[code].defaultColor();
+    if (type == ST_90P) {
+        color = brighten(color, 1.33f);
+    }
+    int index = gSummaryChart::addCalc(code, type, color);
+    return index;
 }
 
 void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF rect)
diff --git a/oscar/Graphs/gPressureChart.h b/oscar/Graphs/gPressureChart.h
index fbfb9822..5ecf5364 100644
--- a/oscar/Graphs/gPressureChart.h
+++ b/oscar/Graphs/gPressureChart.h
@@ -43,6 +43,7 @@ public:
         return day->getCPAPModeStr() + "\n" + day->getPressureSettings() + gSummaryChart::tooltipData(day, idx);
     }
 
+    virtual int addCalc(ChannelID code, SummaryType type);
 };
 
 #endif // GPRESSURECHART_H
diff --git a/oscar/Graphs/gSessionTimesChart.cpp b/oscar/Graphs/gSessionTimesChart.cpp
index 7e380852..29aafb29 100644
--- a/oscar/Graphs/gSessionTimesChart.cpp
+++ b/oscar/Graphs/gSessionTimesChart.cpp
@@ -102,6 +102,17 @@ void gSummaryChart::SetDay(Day *unused_day)
 //QMap<QDate, int> gSummaryChart::dayindex;
 //QList<Day *> gSummaryChart::daylist;
 
+int gSummaryChart::addCalc(ChannelID code, SummaryType type, QColor color)
+{
+    calcitems.append(SummaryCalcItem(code, type, color));
+    return calcitems.size() - 1;  // return the index of the newly appended calc
+}
+
+int gSummaryChart::addCalc(ChannelID code, SummaryType type)
+{
+    return addCalc(code, type, schema::channel[code].defaultColor());
+}
+
 
 bool gSummaryChart::keyPressEvent(QKeyEvent *event, gGraph *graph)
 {
diff --git a/oscar/Graphs/gSessionTimesChart.h b/oscar/Graphs/gSessionTimesChart.h
index 87988313..bdd8bcc8 100644
--- a/oscar/Graphs/gSessionTimesChart.h
+++ b/oscar/Graphs/gSessionTimesChart.h
@@ -189,13 +189,8 @@ public:
         cache.clear();
     }
 
-
-    void addCalc(ChannelID code, SummaryType type, QColor color) {
-        calcitems.append(SummaryCalcItem(code, type, color));
-    }
-    void addCalc(ChannelID code, SummaryType type) {
-        calcitems.append(SummaryCalcItem(code, type, schema::channel[code].defaultColor()));
-    }
+    virtual int addCalc(ChannelID code, SummaryType type, QColor color);
+    virtual int addCalc(ChannelID code, SummaryType type);
 
     virtual Layer * Clone() {
         gSummaryChart * sc = new gSummaryChart(m_label, m_machtype);

From d13109bbeda1b0dbef15227b1999da8ab337d9f7 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 15:28:15 -0400
Subject: [PATCH 03/13] Replace gPressureChart array indices with channel-based
 references.

---
 oscar/Graphs/gPressureChart.cpp | 123 ++++++++++++++++----------------
 oscar/Graphs/gPressureChart.h   |   5 ++
 2 files changed, 67 insertions(+), 61 deletions(-)

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index cac04bfa..bcdca7db 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -12,8 +12,6 @@
 gPressureChart::gPressureChart()
     : gSummaryChart("Pressure", MT_CPAP)
 {
-
-    // Do not reorder these!!! :P
     addCalc(CPAP_Pressure, ST_SETMAX);     // 00
     addCalc(CPAP_Pressure, ST_MID);        // 01
     addCalc(CPAP_Pressure, ST_90P);        // 02
@@ -37,67 +35,68 @@ int gPressureChart::addCalc(ChannelID code, SummaryType type) {
         color = brighten(color, 1.33f);
     }
     int index = gSummaryChart::addCalc(code, type, color);
+    m_calcs[code][type] = index;
     return index;
 }
 
+SummaryCalcItem* gPressureChart::getCalc(ChannelID code, SummaryType type)
+{
+    return &calcitems[m_calcs[code][type]];
+}
+
 void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF 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;
+    SummaryCalcItem* calc;
 
-    float mid = 0;
-
-    if (pressure_cnt > 0) {
-        mid = calcitems[0].mid();
+    calc = getCalc(CPAP_Pressure);
+    if (calc->cnt > 0) {
         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));
+                arg(calc->min,0,'f',1).
+                arg(calc->mid(), 0, 'f', 1).
+                arg(calc->max,0,'f',1));
     }
-    if (pressuremin_cnt > 0) {
+    if (getCalc(CPAP_PressureMin, ST_SETMIN)->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));
+                arg(getCalc(CPAP_PressureMin, ST_SETMIN)->min,0,'f',1).
+                arg(getCalc(CPAP_Pressure, ST_MID)->mid(), 0, 'f', 1).
+                arg(getCalc(CPAP_Pressure, ST_90P)->mid(),0,'f',1).
+                arg(getCalc(CPAP_PressureMax, ST_SETMAX)->max, 0, 'f', 1));
 
     }
-    if (epap_cnt > 0) {
+    calc = getCalc(CPAP_EPAP);
+    if (calc->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));
+                arg(calc->min,0,'f',1).
+                arg(calc->mid(), 0, 'f', 1).
+                arg(calc->max, 0, 'f', 1));
     }
-    if (ipap_cnt > 0) {
+    calc = getCalc(CPAP_IPAP);
+    if (calc->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));
+             arg(calc->min,0,'f',1).
+             arg(calc->mid(), 0, 'f', 1).
+             arg(calc->max, 0, 'f', 1));
     }
-    if (epaplo_cnt > 0) {
+    calc = getCalc(CPAP_EPAPLo);
+    if (calc->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));
+            arg(calc->min,0,'f',1).
+            arg(calc->mid(), 0, 'f', 1).
+            arg(calc->max, 0, 'f', 1));
     }
-
-    if (ipaphi_cnt > 0) {
+    calc = getCalc(CPAP_IPAPHi);
+    if (calc->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));
+            arg(calc->min,0,'f',1).
+            arg(calc->mid(), 0, 'f', 1).
+            arg(calc->max, 0, 'f', 1));
     }
     QString txt = presstr.join(" ");
     graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0);
@@ -110,100 +109,102 @@ void gPressureChart::populate(Day * day, int idx)
     float tmp;
     CPAPMode mode =  (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode));
     QVector<SummaryChartSlice> & slices = cache[idx];
+    SummaryCalcItem* calc;
 
     if (mode == MODE_CPAP) {
+        calc = getCalc(CPAP_Pressure);
         float pr = day->settings_max(CPAP_Pressure);
-        slices.append(SummaryChartSlice(&calcitems[0], pr, pr, schema::channel[CPAP_Pressure].label(), calcitems[0].color));
+        slices.append(SummaryChartSlice(calc, pr, pr, schema::channel[CPAP_Pressure].label(), calc->color));
     } else if (mode == MODE_APAP) {
         float min = day->settings_min(CPAP_PressureMin);
         float max = day->settings_max(CPAP_PressureMax);
 
         tmp = min;
 
-        slices.append(SummaryChartSlice(&calcitems[3], min, min, schema::channel[CPAP_PressureMin].label(), calcitems[3].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_PressureMin, ST_SETMIN), min, min, schema::channel[CPAP_PressureMin].label(), getCalc(CPAP_PressureMin, ST_SETMIN)->color));
         if (!day->summaryOnly()) {
             float med = day->calcMiddle(CPAP_Pressure);
-            slices.append(SummaryChartSlice(&calcitems[1], med, med - tmp, day->calcMiddleLabel(CPAP_Pressure), calcitems[1].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_Pressure, ST_MID), med, med - tmp, day->calcMiddleLabel(CPAP_Pressure), getCalc(CPAP_Pressure, ST_MID)->color));
             tmp += med - tmp;
 
             float p90 = day->calcPercentile(CPAP_Pressure);
-            slices.append(SummaryChartSlice(&calcitems[2], p90, p90 - tmp, day->calcPercentileLabel(CPAP_Pressure), calcitems[2].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_Pressure, ST_90P), p90, p90 - tmp, day->calcPercentileLabel(CPAP_Pressure), getCalc(CPAP_Pressure, ST_90P)->color));
             tmp += p90 - tmp;
         }
-        slices.append(SummaryChartSlice(&calcitems[4], max, max - tmp, schema::channel[CPAP_PressureMax].label(), calcitems[4].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_PressureMax, ST_SETMAX), max, max - tmp, schema::channel[CPAP_PressureMax].label(), getCalc(CPAP_PressureMax, ST_SETMAX)->color));
 
     } else if (mode == MODE_BILEVEL_FIXED) {
         float epap = day->settings_max(CPAP_EPAP);
         float ipap = day->settings_max(CPAP_IPAP);
 
-        slices.append(SummaryChartSlice(&calcitems[5], epap, epap, schema::channel[CPAP_EPAP].label(), calcitems[5].color));
-        slices.append(SummaryChartSlice(&calcitems[6], ipap, ipap - epap, schema::channel[CPAP_IPAP].label(), calcitems[6].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_EPAP), epap, epap, schema::channel[CPAP_EPAP].label(), getCalc(CPAP_EPAP)->color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_IPAP), ipap, ipap - epap, schema::channel[CPAP_IPAP].label(), getCalc(CPAP_IPAP)->color));
 
     } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
         float epap = day->settings_max(CPAP_EPAPLo);
         tmp = epap;
         float ipap = day->settings_max(CPAP_IPAPHi);
 
-        slices.append(SummaryChartSlice(&calcitems[7], epap, epap, schema::channel[CPAP_EPAPLo].label(), calcitems[7].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_EPAPLo), epap, epap, schema::channel[CPAP_EPAPLo].label(), getCalc(CPAP_EPAPLo)->color));
         if (!day->summaryOnly()) {
 
             float e50 = day->calcMiddle(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[9], e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), calcitems[9].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_MID), e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_MID)->color));
             tmp += e50 - tmp;
 
             float e90 = day->calcPercentile(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[10], e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), calcitems[10].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_90P), e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_90P)->color));
             tmp += e90 - tmp;
 
             float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_MID), i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_MID)->color));
             tmp += i50 - tmp;
 
             float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_90P), i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_90P)->color));
             tmp += i90 - tmp;
         }
-        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_IPAPHi), ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), getCalc(CPAP_IPAPHi)->color));
     } else if ((mode == MODE_BILEVEL_AUTO_VARIABLE_PS) || (mode == MODE_ASV_VARIABLE_EPAP)) {
         float epap = day->settings_max(CPAP_EPAPLo);
         tmp = epap;
 
-        slices.append(SummaryChartSlice(&calcitems[7], epap, epap, schema::channel[CPAP_EPAPLo].label(), calcitems[7].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_EPAPLo), epap, epap, schema::channel[CPAP_EPAPLo].label(), getCalc(CPAP_EPAPLo)->color));
         if (!day->summaryOnly()) {
             float e50 = day->calcMiddle(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[9], e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), calcitems[9].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_MID), e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_MID)->color));
             tmp += e50 - tmp;
 
             float e90 = day->calcPercentile(CPAP_EPAP);
-            slices.append(SummaryChartSlice(&calcitems[10], e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), calcitems[10].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_90P), e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_90P)->color));
             tmp += e90 - tmp;
 
             float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_MID), i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_MID)->color));
             tmp += i50 - tmp;
 
             float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_90P), i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_90P)->color));
             tmp += i90 - tmp;
         }
         float ipap = day->settings_max(CPAP_IPAPHi);
-        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_IPAPHi), ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), getCalc(CPAP_IPAPHi)->color));
     } else if (mode == MODE_ASV) {
         float epap = day->settings_max(CPAP_EPAP);
         tmp = epap;
 
-        slices.append(SummaryChartSlice(&calcitems[5], epap, epap, schema::channel[CPAP_EPAP].label(), calcitems[5].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_EPAP), epap, epap, schema::channel[CPAP_EPAP].label(), getCalc(CPAP_EPAP)->color));
         if (!day->summaryOnly()) {
             float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[11], i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), calcitems[11].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_MID), i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_MID)->color));
             tmp += i50 - tmp;
 
             float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(&calcitems[12], i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), calcitems[12].color));
+            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_90P), i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_90P)->color));
             tmp += i90 - tmp;
         }
         float ipap = day->settings_max(CPAP_IPAPHi);
-        slices.append(SummaryChartSlice(&calcitems[8], ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), calcitems[8].color));
+        slices.append(SummaryChartSlice(getCalc(CPAP_IPAPHi), ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), getCalc(CPAP_IPAPHi)->color));
     }
 
 }
diff --git a/oscar/Graphs/gPressureChart.h b/oscar/Graphs/gPressureChart.h
index 5ecf5364..eff94267 100644
--- a/oscar/Graphs/gPressureChart.h
+++ b/oscar/Graphs/gPressureChart.h
@@ -44,6 +44,11 @@ public:
     }
 
     virtual int addCalc(ChannelID code, SummaryType type);
+
+protected:
+    SummaryCalcItem* getCalc(ChannelID code, SummaryType type = ST_SETMAX);
+
+    QHash<ChannelID,QHash<SummaryType,int>> m_calcs;
 };
 
 #endif // GPRESSURECHART_H

From c5768a64fe9a0e1d0750c4a64f11550a829d0bf8 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 16:06:08 -0400
Subject: [PATCH 04/13] Simplify gPressureChart upper label formatting.

---
 oscar/Graphs/gPressureChart.cpp | 94 +++++++++++++++------------------
 oscar/Graphs/gPressureChart.h   |  1 +
 2 files changed, 45 insertions(+), 50 deletions(-)

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index bcdca7db..fee63208 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -12,50 +12,53 @@
 gPressureChart::gPressureChart()
     : gSummaryChart("Pressure", MT_CPAP)
 {
-    addCalc(CPAP_Pressure, ST_SETMAX);     // 00
-    addCalc(CPAP_Pressure, ST_MID);        // 01
-    addCalc(CPAP_Pressure, ST_90P);        // 02
-    addCalc(CPAP_PressureMin, ST_SETMIN);  // 03
-    addCalc(CPAP_PressureMax, ST_SETMAX);  // 04
+    addCalc(CPAP_Pressure, ST_SETMAX);
+    addCalc(CPAP_Pressure, ST_MID);
+    addCalc(CPAP_Pressure, ST_90P);
+    addCalc(CPAP_PressureMin, ST_SETMIN);
+    addCalc(CPAP_PressureMax, ST_SETMAX);
 
-    addCalc(CPAP_EPAP, ST_SETMAX);      // 05
-    addCalc(CPAP_IPAP, ST_SETMAX);      // 06
-    addCalc(CPAP_EPAPLo, ST_SETMAX);    // 07
-    addCalc(CPAP_IPAPHi, ST_SETMAX);    // 08
+    addCalc(CPAP_EPAP, ST_SETMAX);
+    addCalc(CPAP_IPAP, ST_SETMAX);
+    addCalc(CPAP_EPAPLo, ST_SETMAX);
+    addCalc(CPAP_IPAPHi, ST_SETMAX);
 
-    addCalc(CPAP_EPAP, ST_MID);         // 09
-    addCalc(CPAP_EPAP, ST_90P);         // 10
-    addCalc(CPAP_IPAP, ST_MID);         // 11
-    addCalc(CPAP_IPAP, ST_90P);         // 12
+    addCalc(CPAP_EPAP, ST_MID);
+    addCalc(CPAP_EPAP, ST_90P);
+    addCalc(CPAP_IPAP, ST_MID);
+    addCalc(CPAP_IPAP, ST_90P);
 }
 
-int gPressureChart::addCalc(ChannelID code, SummaryType type) {
+
+int gPressureChart::addCalc(ChannelID code, SummaryType type)
+{
     QColor color = schema::channel[code].defaultColor();
     if (type == ST_90P) {
         color = brighten(color, 1.33f);
     }
+
     int index = gSummaryChart::addCalc(code, type, color);
+
+    // Save the code and type used to add this calculation so that getCalc()
+    // can retrieve it by code and type instead of by hard-coded index.
     m_calcs[code][type] = index;
+
     return index;
 }
 
+
 SummaryCalcItem* gPressureChart::getCalc(ChannelID code, SummaryType type)
 {
     return &calcitems[m_calcs[code][type]];
 }
 
+
 void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF rect)
 {
     QStringList presstr;
-    SummaryCalcItem* calc;
 
-    calc = getCalc(CPAP_Pressure);
-    if (calc->cnt > 0) {
-        presstr.append(QString("%1 %2/%3/%4").
-                arg(STR_TR_CPAP).
-                arg(calc->min,0,'f',1).
-                arg(calc->mid(), 0, 'f', 1).
-                arg(calc->max,0,'f',1));
+    if (getCalc(CPAP_Pressure)->cnt > 0) {
+        presstr.append(channelRange(CPAP_Pressure, STR_TR_CPAP));
     }
     if (getCalc(CPAP_PressureMin, ST_SETMIN)->cnt > 0) {
         presstr.append(QString("%1 %2/%3/%4/%5").
@@ -66,37 +69,17 @@ void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF rect)
                 arg(getCalc(CPAP_PressureMax, ST_SETMAX)->max, 0, 'f', 1));
 
     }
-    calc = getCalc(CPAP_EPAP);
-    if (calc->cnt > 0) {
-        presstr.append(QString("%1 %2/%3/%4").
-                arg(STR_TR_EPAP).
-                arg(calc->min,0,'f',1).
-                arg(calc->mid(), 0, 'f', 1).
-                arg(calc->max, 0, 'f', 1));
+    if (getCalc(CPAP_EPAP)->cnt > 0) {
+        presstr.append(channelRange(CPAP_EPAP, STR_TR_EPAP));
     }
-    calc = getCalc(CPAP_IPAP);
-    if (calc->cnt > 0) {
-        presstr.append(QString("%1 %2/%3/%4").
-             arg(STR_TR_IPAP).
-             arg(calc->min,0,'f',1).
-             arg(calc->mid(), 0, 'f', 1).
-             arg(calc->max, 0, 'f', 1));
+    if (getCalc(CPAP_IPAP)->cnt > 0) {
+        presstr.append(channelRange(CPAP_IPAP, STR_TR_IPAP));
     }
-    calc = getCalc(CPAP_EPAPLo);
-    if (calc->cnt > 0) {
-        presstr.append(QString("%1 %2/%3/%4").
-            arg(STR_TR_EPAPLo).
-            arg(calc->min,0,'f',1).
-            arg(calc->mid(), 0, 'f', 1).
-            arg(calc->max, 0, 'f', 1));
+    if (getCalc(CPAP_EPAPLo)->cnt > 0) {
+        presstr.append(channelRange(CPAP_EPAPLo, STR_TR_EPAPLo));
     }
-    calc = getCalc(CPAP_IPAPHi);
-    if (calc->cnt > 0) {
-        presstr.append(QString("%1 %2/%3/%4").
-            arg(STR_TR_IPAPHi).
-            arg(calc->min,0,'f',1).
-            arg(calc->mid(), 0, 'f', 1).
-            arg(calc->max, 0, 'f', 1));
+    if (getCalc(CPAP_IPAPHi)->cnt > 0) {
+        presstr.append(channelRange(CPAP_IPAPHi, STR_TR_IPAPHi));
     }
     QString txt = presstr.join(" ");
     graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0);
@@ -104,6 +87,17 @@ void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF rect)
 }
 
 
+QString gPressureChart::channelRange(ChannelID code, const QString & label)
+{
+    SummaryCalcItem* calc = getCalc(code);
+    return QString("%1 %2/%3/%4").
+            arg(label).
+            arg(calc->min, 0, 'f', 1).
+            arg(calc->mid(), 0, 'f', 1).
+            arg(calc->max, 0, 'f', 1);
+}
+
+
 void gPressureChart::populate(Day * day, int idx)
 {
     float tmp;
diff --git a/oscar/Graphs/gPressureChart.h b/oscar/Graphs/gPressureChart.h
index eff94267..46e1a76b 100644
--- a/oscar/Graphs/gPressureChart.h
+++ b/oscar/Graphs/gPressureChart.h
@@ -47,6 +47,7 @@ public:
 
 protected:
     SummaryCalcItem* getCalc(ChannelID code, SummaryType type = ST_SETMAX);
+    QString channelRange(ChannelID code, const QString & label);
 
     QHash<ChannelID,QHash<SummaryType,int>> m_calcs;
 };

From 33eacab53f0d4f84c77fec52152bdc777ef23d09 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 16:46:25 -0400
Subject: [PATCH 05/13] Refactor gPressureChart::populate().

---
 oscar/Graphs/gPressureChart.cpp | 98 ++++++++++++++++++---------------
 oscar/Graphs/gPressureChart.h   |  6 ++
 2 files changed, 59 insertions(+), 45 deletions(-)

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index fee63208..85da32be 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -98,107 +98,115 @@ QString gPressureChart::channelRange(ChannelID code, const QString & label)
 }
 
 
+void gPressureChart::addSlice(float value, ChannelID code, SummaryType type)
+{
+    SummaryCalcItem* calc = getCalc(code, type);
+    float height = value - m_height;
+    QString label;
+
+    switch (type) {
+    case ST_SETMIN:
+    case ST_SETMAX:
+        label = schema::channel[code].label();
+        break;
+    case ST_MID:
+        label = m_day->calcMiddleLabel(code);
+        break;
+    case ST_90P:
+        label = m_day->calcPercentileLabel(code);
+        break;
+    default:
+        qWarning() << "Unsupported summary type in gPressureChart";
+        break;
+    }
+
+    m_slices->append(SummaryChartSlice(calc, value, height, label, calc->color));
+    m_height += height;
+}
+
+
 void gPressureChart::populate(Day * day, int idx)
 {
-    float tmp;
     CPAPMode mode =  (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode));
-    QVector<SummaryChartSlice> & slices = cache[idx];
-    SummaryCalcItem* calc;
+    m_day = day;
+    m_slices = &cache[idx];
+    m_height = 0;
 
     if (mode == MODE_CPAP) {
-        calc = getCalc(CPAP_Pressure);
         float pr = day->settings_max(CPAP_Pressure);
-        slices.append(SummaryChartSlice(calc, pr, pr, schema::channel[CPAP_Pressure].label(), calc->color));
+        addSlice(pr, CPAP_Pressure);
     } else if (mode == MODE_APAP) {
         float min = day->settings_min(CPAP_PressureMin);
         float max = day->settings_max(CPAP_PressureMax);
 
-        tmp = min;
-
-        slices.append(SummaryChartSlice(getCalc(CPAP_PressureMin, ST_SETMIN), min, min, schema::channel[CPAP_PressureMin].label(), getCalc(CPAP_PressureMin, ST_SETMIN)->color));
+        addSlice(min, CPAP_PressureMin, ST_SETMIN);
         if (!day->summaryOnly()) {
             float med = day->calcMiddle(CPAP_Pressure);
-            slices.append(SummaryChartSlice(getCalc(CPAP_Pressure, ST_MID), med, med - tmp, day->calcMiddleLabel(CPAP_Pressure), getCalc(CPAP_Pressure, ST_MID)->color));
-            tmp += med - tmp;
+            addSlice(med, CPAP_Pressure, ST_MID);
 
             float p90 = day->calcPercentile(CPAP_Pressure);
-            slices.append(SummaryChartSlice(getCalc(CPAP_Pressure, ST_90P), p90, p90 - tmp, day->calcPercentileLabel(CPAP_Pressure), getCalc(CPAP_Pressure, ST_90P)->color));
-            tmp += p90 - tmp;
+            addSlice(p90, CPAP_Pressure, ST_90P);
         }
-        slices.append(SummaryChartSlice(getCalc(CPAP_PressureMax, ST_SETMAX), max, max - tmp, schema::channel[CPAP_PressureMax].label(), getCalc(CPAP_PressureMax, ST_SETMAX)->color));
+        addSlice(max, CPAP_PressureMax, ST_SETMAX);
 
     } else if (mode == MODE_BILEVEL_FIXED) {
         float epap = day->settings_max(CPAP_EPAP);
         float ipap = day->settings_max(CPAP_IPAP);
 
-        slices.append(SummaryChartSlice(getCalc(CPAP_EPAP), epap, epap, schema::channel[CPAP_EPAP].label(), getCalc(CPAP_EPAP)->color));
-        slices.append(SummaryChartSlice(getCalc(CPAP_IPAP), ipap, ipap - epap, schema::channel[CPAP_IPAP].label(), getCalc(CPAP_IPAP)->color));
+        addSlice(epap, CPAP_EPAP);
+        addSlice(ipap, CPAP_IPAP);
 
     } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
         float epap = day->settings_max(CPAP_EPAPLo);
-        tmp = epap;
         float ipap = day->settings_max(CPAP_IPAPHi);
 
-        slices.append(SummaryChartSlice(getCalc(CPAP_EPAPLo), epap, epap, schema::channel[CPAP_EPAPLo].label(), getCalc(CPAP_EPAPLo)->color));
+        addSlice(epap, CPAP_EPAPLo);
         if (!day->summaryOnly()) {
 
             float e50 = day->calcMiddle(CPAP_EPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_MID), e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_MID)->color));
-            tmp += e50 - tmp;
+            addSlice(e50, CPAP_EPAP, ST_MID);
 
             float e90 = day->calcPercentile(CPAP_EPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_90P), e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_90P)->color));
-            tmp += e90 - tmp;
+            addSlice(e90, CPAP_EPAP, ST_90P);
 
             float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_MID), i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_MID)->color));
-            tmp += i50 - tmp;
+            addSlice(i50, CPAP_IPAP, ST_MID);
 
             float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_90P), i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_90P)->color));
-            tmp += i90 - tmp;
+            addSlice(i90, CPAP_IPAP, ST_90P);
         }
-        slices.append(SummaryChartSlice(getCalc(CPAP_IPAPHi), ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), getCalc(CPAP_IPAPHi)->color));
+        addSlice(ipap, CPAP_IPAPHi);
     } else if ((mode == MODE_BILEVEL_AUTO_VARIABLE_PS) || (mode == MODE_ASV_VARIABLE_EPAP)) {
         float epap = day->settings_max(CPAP_EPAPLo);
-        tmp = epap;
 
-        slices.append(SummaryChartSlice(getCalc(CPAP_EPAPLo), epap, epap, schema::channel[CPAP_EPAPLo].label(), getCalc(CPAP_EPAPLo)->color));
+        addSlice(epap, CPAP_EPAPLo);
         if (!day->summaryOnly()) {
             float e50 = day->calcMiddle(CPAP_EPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_MID), e50, e50 - tmp, day->calcMiddleLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_MID)->color));
-            tmp += e50 - tmp;
+            addSlice(e50, CPAP_EPAP, ST_MID);
 
             float e90 = day->calcPercentile(CPAP_EPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_EPAP, ST_90P), e90, e90 - tmp, day->calcPercentileLabel(CPAP_EPAP), getCalc(CPAP_EPAP, ST_90P)->color));
-            tmp += e90 - tmp;
+            addSlice(e90, CPAP_EPAP, ST_90P);
 
             float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_MID), i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_MID)->color));
-            tmp += i50 - tmp;
+            addSlice(i50, CPAP_IPAP, ST_MID);
 
             float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_90P), i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_90P)->color));
-            tmp += i90 - tmp;
+            addSlice(i90, CPAP_IPAP, ST_90P);
         }
         float ipap = day->settings_max(CPAP_IPAPHi);
-        slices.append(SummaryChartSlice(getCalc(CPAP_IPAPHi), ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), getCalc(CPAP_IPAPHi)->color));
+        addSlice(ipap, CPAP_IPAPHi);
     } else if (mode == MODE_ASV) {
         float epap = day->settings_max(CPAP_EPAP);
-        tmp = epap;
 
-        slices.append(SummaryChartSlice(getCalc(CPAP_EPAP), epap, epap, schema::channel[CPAP_EPAP].label(), getCalc(CPAP_EPAP)->color));
+        addSlice(epap, CPAP_EPAP);
         if (!day->summaryOnly()) {
             float i50 = day->calcMiddle(CPAP_IPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_MID), i50, i50 - tmp, day->calcMiddleLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_MID)->color));
-            tmp += i50 - tmp;
+            addSlice(i50, CPAP_IPAP, ST_MID);
 
             float i90 = day->calcPercentile(CPAP_IPAP);
-            slices.append(SummaryChartSlice(getCalc(CPAP_IPAP, ST_90P), i90, i90 - tmp, day->calcPercentileLabel(CPAP_IPAP), getCalc(CPAP_IPAP, ST_90P)->color));
-            tmp += i90 - tmp;
+            addSlice(i90, CPAP_IPAP, ST_90P);
         }
         float ipap = day->settings_max(CPAP_IPAPHi);
-        slices.append(SummaryChartSlice(getCalc(CPAP_IPAPHi), ipap, ipap - tmp, schema::channel[CPAP_IPAPHi].label(), getCalc(CPAP_IPAPHi)->color));
+        addSlice(ipap, CPAP_IPAPHi);
     }
-
 }
diff --git a/oscar/Graphs/gPressureChart.h b/oscar/Graphs/gPressureChart.h
index 46e1a76b..692b11ad 100644
--- a/oscar/Graphs/gPressureChart.h
+++ b/oscar/Graphs/gPressureChart.h
@@ -48,8 +48,14 @@ public:
 protected:
     SummaryCalcItem* getCalc(ChannelID code, SummaryType type = ST_SETMAX);
     QString channelRange(ChannelID code, const QString & label);
+    void addSlice(float value, ChannelID code, SummaryType type = ST_SETMAX);
 
     QHash<ChannelID,QHash<SummaryType,int>> m_calcs;
+
+    // State passed between populate() and addSlice():
+    Day* m_day;
+    QVector<SummaryChartSlice>* m_slices;
+    float m_height;
 };
 
 #endif // GPRESSURECHART_H

From 670693dd5f12f9c077fc15fddb6e94ad47e72ebd Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 16:55:56 -0400
Subject: [PATCH 06/13] Move gPressureChart value calculation into addSlice.

---
 oscar/Graphs/gPressureChart.cpp | 97 ++++++++++++---------------------
 oscar/Graphs/gPressureChart.h   |  2 +-
 2 files changed, 35 insertions(+), 64 deletions(-)

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index 85da32be..55d3e2ea 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -98,21 +98,26 @@ QString gPressureChart::channelRange(ChannelID code, const QString & label)
 }
 
 
-void gPressureChart::addSlice(float value, ChannelID code, SummaryType type)
+void gPressureChart::addSlice(ChannelID code, SummaryType type)
 {
-    SummaryCalcItem* calc = getCalc(code, type);
-    float height = value - m_height;
+    float value = 0;
     QString label;
 
     switch (type) {
     case ST_SETMIN:
+        value = m_day->settings_min(code);
+        label = schema::channel[code].label();
+        break;
     case ST_SETMAX:
+        value = m_day->settings_max(code);
         label = schema::channel[code].label();
         break;
     case ST_MID:
+        value = m_day->calcMiddle(code);
         label = m_day->calcMiddleLabel(code);
         break;
     case ST_90P:
+        value = m_day->calcPercentile(code);
         label = m_day->calcPercentileLabel(code);
         break;
     default:
@@ -120,6 +125,9 @@ void gPressureChart::addSlice(float value, ChannelID code, SummaryType type)
         break;
     }
 
+    SummaryCalcItem* calc = getCalc(code, type);
+    float height = value - m_height;
+
     m_slices->append(SummaryChartSlice(calc, value, height, label, calc->color));
     m_height += height;
 }
@@ -133,80 +141,43 @@ void gPressureChart::populate(Day * day, int idx)
     m_height = 0;
 
     if (mode == MODE_CPAP) {
-        float pr = day->settings_max(CPAP_Pressure);
-        addSlice(pr, CPAP_Pressure);
+        addSlice(CPAP_Pressure);
     } else if (mode == MODE_APAP) {
-        float min = day->settings_min(CPAP_PressureMin);
-        float max = day->settings_max(CPAP_PressureMax);
-
-        addSlice(min, CPAP_PressureMin, ST_SETMIN);
+        addSlice(CPAP_PressureMin, ST_SETMIN);
         if (!day->summaryOnly()) {
-            float med = day->calcMiddle(CPAP_Pressure);
-            addSlice(med, CPAP_Pressure, ST_MID);
-
-            float p90 = day->calcPercentile(CPAP_Pressure);
-            addSlice(p90, CPAP_Pressure, ST_90P);
+            addSlice(CPAP_Pressure, ST_MID);
+            addSlice(CPAP_Pressure, ST_90P);
         }
-        addSlice(max, CPAP_PressureMax, ST_SETMAX);
+        addSlice(CPAP_PressureMax, ST_SETMAX);
 
     } else if (mode == MODE_BILEVEL_FIXED) {
-        float epap = day->settings_max(CPAP_EPAP);
-        float ipap = day->settings_max(CPAP_IPAP);
-
-        addSlice(epap, CPAP_EPAP);
-        addSlice(ipap, CPAP_IPAP);
+        addSlice(CPAP_EPAP);
+        addSlice(CPAP_IPAP);
 
     } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
-        float epap = day->settings_max(CPAP_EPAPLo);
-        float ipap = day->settings_max(CPAP_IPAPHi);
-
-        addSlice(epap, CPAP_EPAPLo);
+        addSlice(CPAP_EPAPLo);
         if (!day->summaryOnly()) {
-
-            float e50 = day->calcMiddle(CPAP_EPAP);
-            addSlice(e50, CPAP_EPAP, ST_MID);
-
-            float e90 = day->calcPercentile(CPAP_EPAP);
-            addSlice(e90, CPAP_EPAP, ST_90P);
-
-            float i50 = day->calcMiddle(CPAP_IPAP);
-            addSlice(i50, CPAP_IPAP, ST_MID);
-
-            float i90 = day->calcPercentile(CPAP_IPAP);
-            addSlice(i90, CPAP_IPAP, ST_90P);
+            addSlice(CPAP_EPAP, ST_MID);
+            addSlice(CPAP_EPAP, ST_90P);
+            addSlice(CPAP_IPAP, ST_MID);
+            addSlice(CPAP_IPAP, ST_90P);
         }
-        addSlice(ipap, CPAP_IPAPHi);
+        addSlice(CPAP_IPAPHi);
     } else if ((mode == MODE_BILEVEL_AUTO_VARIABLE_PS) || (mode == MODE_ASV_VARIABLE_EPAP)) {
-        float epap = day->settings_max(CPAP_EPAPLo);
-
-        addSlice(epap, CPAP_EPAPLo);
+        addSlice(CPAP_EPAPLo);
         if (!day->summaryOnly()) {
-            float e50 = day->calcMiddle(CPAP_EPAP);
-            addSlice(e50, CPAP_EPAP, ST_MID);
-
-            float e90 = day->calcPercentile(CPAP_EPAP);
-            addSlice(e90, CPAP_EPAP, ST_90P);
-
-            float i50 = day->calcMiddle(CPAP_IPAP);
-            addSlice(i50, CPAP_IPAP, ST_MID);
-
-            float i90 = day->calcPercentile(CPAP_IPAP);
-            addSlice(i90, CPAP_IPAP, ST_90P);
+            addSlice(CPAP_EPAP, ST_MID);
+            addSlice(CPAP_EPAP, ST_90P);
+            addSlice(CPAP_IPAP, ST_MID);
+            addSlice(CPAP_IPAP, ST_90P);
         }
-        float ipap = day->settings_max(CPAP_IPAPHi);
-        addSlice(ipap, CPAP_IPAPHi);
+        addSlice(CPAP_IPAPHi);
     } else if (mode == MODE_ASV) {
-        float epap = day->settings_max(CPAP_EPAP);
-
-        addSlice(epap, CPAP_EPAP);
+        addSlice(CPAP_EPAP);
         if (!day->summaryOnly()) {
-            float i50 = day->calcMiddle(CPAP_IPAP);
-            addSlice(i50, CPAP_IPAP, ST_MID);
-
-            float i90 = day->calcPercentile(CPAP_IPAP);
-            addSlice(i90, CPAP_IPAP, ST_90P);
+            addSlice(CPAP_IPAP, ST_MID);
+            addSlice(CPAP_IPAP, ST_90P);
         }
-        float ipap = day->settings_max(CPAP_IPAPHi);
-        addSlice(ipap, CPAP_IPAPHi);
+        addSlice(CPAP_IPAPHi);
     }
 }
diff --git a/oscar/Graphs/gPressureChart.h b/oscar/Graphs/gPressureChart.h
index 692b11ad..842d1c94 100644
--- a/oscar/Graphs/gPressureChart.h
+++ b/oscar/Graphs/gPressureChart.h
@@ -48,7 +48,7 @@ public:
 protected:
     SummaryCalcItem* getCalc(ChannelID code, SummaryType type = ST_SETMAX);
     QString channelRange(ChannelID code, const QString & label);
-    void addSlice(float value, ChannelID code, SummaryType type = ST_SETMAX);
+    void addSlice(ChannelID code, SummaryType type = ST_SETMAX);
 
     QHash<ChannelID,QHash<SummaryType,int>> m_calcs;
 

From 4a5322c3502b2f70cdfac74918788a475c73738c Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 17:35:50 -0400
Subject: [PATCH 07/13] Fix overview pressure chart for PRS1 pressure setting
 channels.

---
 oscar/Graphs/gPressureChart.cpp | 71 ++++++++++++++++++++++++++++-----
 1 file changed, 61 insertions(+), 10 deletions(-)

diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index 55d3e2ea..83b94427 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -27,6 +27,14 @@ gPressureChart::gPressureChart()
     addCalc(CPAP_EPAP, ST_90P);
     addCalc(CPAP_IPAP, ST_MID);
     addCalc(CPAP_IPAP, ST_90P);
+
+    // PRS1 reports pressure adjustments instead of observed pressures on some machines
+    addCalc(CPAP_PressureSet, ST_MID);
+    addCalc(CPAP_PressureSet, ST_90P);
+    addCalc(CPAP_EPAPSet, ST_MID);
+    addCalc(CPAP_EPAPSet, ST_90P);
+    addCalc(CPAP_IPAPSet, ST_MID);
+    addCalc(CPAP_IPAPSet, ST_90P);
 }
 
 
@@ -60,27 +68,50 @@ void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRectF rect)
     if (getCalc(CPAP_Pressure)->cnt > 0) {
         presstr.append(channelRange(CPAP_Pressure, STR_TR_CPAP));
     }
+
     if (getCalc(CPAP_PressureMin, ST_SETMIN)->cnt > 0) {
+        // TODO: If using machines from different manufacturers in an overview,
+        // the below may not accurately find the APAP pressure channel for all
+        // days; but it only affects the summary label at the top.
+        ChannelID pressure = CPAP_Pressure;
+        if (getCalc(CPAP_PressureSet, ST_MID)->cnt > 0) {
+            pressure = CPAP_PressureSet;
+        }
         presstr.append(QString("%1 %2/%3/%4/%5").
                 arg(STR_TR_APAP).
                 arg(getCalc(CPAP_PressureMin, ST_SETMIN)->min,0,'f',1).
-                arg(getCalc(CPAP_Pressure, ST_MID)->mid(), 0, 'f', 1).
-                arg(getCalc(CPAP_Pressure, ST_90P)->mid(),0,'f',1).
+                arg(getCalc(pressure, ST_MID)->mid(), 0, 'f', 1).
+                arg(getCalc(pressure, ST_90P)->mid(),0,'f',1).
                 arg(getCalc(CPAP_PressureMax, ST_SETMAX)->max, 0, 'f', 1));
 
     }
+
     if (getCalc(CPAP_EPAP)->cnt > 0) {
-        presstr.append(channelRange(CPAP_EPAP, STR_TR_EPAP));
+        // See CPAP_PressureSet note above.
+        ChannelID epap = CPAP_EPAP;
+        if (getCalc(CPAP_EPAPSet, ST_MID)->cnt > 0) {
+            epap = CPAP_EPAPSet;
+        }
+        presstr.append(channelRange(epap, STR_TR_EPAP));
     }
+
     if (getCalc(CPAP_IPAP)->cnt > 0) {
-        presstr.append(channelRange(CPAP_IPAP, STR_TR_IPAP));
+        // See CPAP_PressureSet note above.
+        ChannelID ipap = CPAP_IPAP;
+        if (getCalc(CPAP_IPAPSet, ST_MID)->cnt > 0) {
+            ipap = CPAP_IPAPSet;
+        }
+        presstr.append(channelRange(ipap, STR_TR_IPAP));
     }
+
     if (getCalc(CPAP_EPAPLo)->cnt > 0) {
         presstr.append(channelRange(CPAP_EPAPLo, STR_TR_EPAPLo));
     }
+
     if (getCalc(CPAP_IPAPHi)->cnt > 0) {
         presstr.append(channelRange(CPAP_IPAPHi, STR_TR_IPAPHi));
     }
+
     QString txt = presstr.join(" ");
     graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0);
 
@@ -142,11 +173,17 @@ void gPressureChart::populate(Day * day, int idx)
 
     if (mode == MODE_CPAP) {
         addSlice(CPAP_Pressure);
+
     } else if (mode == MODE_APAP) {
         addSlice(CPAP_PressureMin, ST_SETMIN);
         if (!day->summaryOnly()) {
-            addSlice(CPAP_Pressure, ST_MID);
-            addSlice(CPAP_Pressure, ST_90P);
+            // Handle PRS1 pressure adjustments reported separately from average (EPAP) pressure
+            ChannelID pressure = CPAP_Pressure;
+            if (m_day->channelHasData(CPAP_PressureSet)) {
+                pressure = CPAP_PressureSet;
+            }
+            addSlice(pressure, ST_MID);
+            addSlice(pressure, ST_90P);
         }
         addSlice(CPAP_PressureMax, ST_SETMAX);
 
@@ -163,15 +200,26 @@ void gPressureChart::populate(Day * day, int idx)
             addSlice(CPAP_IPAP, ST_90P);
         }
         addSlice(CPAP_IPAPHi);
+
     } else if ((mode == MODE_BILEVEL_AUTO_VARIABLE_PS) || (mode == MODE_ASV_VARIABLE_EPAP)) {
         addSlice(CPAP_EPAPLo);
         if (!day->summaryOnly()) {
-            addSlice(CPAP_EPAP, ST_MID);
-            addSlice(CPAP_EPAP, ST_90P);
-            addSlice(CPAP_IPAP, ST_MID);
-            addSlice(CPAP_IPAP, ST_90P);
+            // Handle PRS1 pressure adjustments when reported instead of observed pressures
+            ChannelID epap = CPAP_EPAP;
+            if (m_day->channelHasData(CPAP_EPAPSet)) {
+                epap = CPAP_EPAPSet;
+            }
+            ChannelID ipap = CPAP_IPAP;
+            if (m_day->channelHasData(CPAP_IPAPSet)) {
+                ipap = CPAP_IPAPSet;
+            }
+            addSlice(epap, ST_MID);
+            addSlice(epap, ST_90P);
+            addSlice(ipap, ST_MID);
+            addSlice(ipap, ST_90P);
         }
         addSlice(CPAP_IPAPHi);
+
     } else if (mode == MODE_ASV) {
         addSlice(CPAP_EPAP);
         if (!day->summaryOnly()) {
@@ -179,5 +227,8 @@ void gPressureChart::populate(Day * day, int idx)
             addSlice(CPAP_IPAP, ST_90P);
         }
         addSlice(CPAP_IPAPHi);
+
+    } else if (mode == MODE_AVAPS) {
+        // TODO
     }
 }

From a8cd0a72b46c853fefc07fc3e65e5daa1b2a001b Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 20:13:26 -0400
Subject: [PATCH 08/13] Add support for AVAPS in overview pressure chart.

---
 Htmldocs/release_notes.html     | 2 ++
 oscar/Graphs/gPressureChart.cpp | 7 ++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/Htmldocs/release_notes.html b/Htmldocs/release_notes.html
index 50d8d281..b35375ed 100644
--- a/Htmldocs/release_notes.html
+++ b/Htmldocs/release_notes.html
@@ -21,6 +21,8 @@
         </ul>
       <li>[new] Add the "peak flow" channel reported by pre-DreamStation ventilators.</li>
       <li>[new] Automatically detect and resolve graphics-related crashes on Windows.</li>
+      <li>[new] Support AVAPS in the Overview pressure chart.</li>
+      <li>[fix] Fix missing bars in the Overview pressure chart for Philips Respironics devices.</li>
       <li>[fix] Add support for the Bi-Flex lock setting on pre-DreamStation ventilators.</li>
       <li>[fix] Fix the pressure waveform scale for the BiPAP autoSV Advanced 30 (960T)</li>
       <li>[fix] Add support for rise time mode on DreamStation BiPAP devices (600X-700X).</li>
diff --git a/oscar/Graphs/gPressureChart.cpp b/oscar/Graphs/gPressureChart.cpp
index 83b94427..e7f8b98d 100644
--- a/oscar/Graphs/gPressureChart.cpp
+++ b/oscar/Graphs/gPressureChart.cpp
@@ -229,6 +229,11 @@ void gPressureChart::populate(Day * day, int idx)
         addSlice(CPAP_IPAPHi);
 
     } else if (mode == MODE_AVAPS) {
-        // TODO
+        addSlice(CPAP_EPAP);
+        if (!day->summaryOnly()) {
+            addSlice(CPAP_IPAP, ST_MID);
+            addSlice(CPAP_IPAP, ST_90P);
+        }
+        addSlice(CPAP_IPAPHi);
     }
 }

From 0680424759a877d7f23304f553a3350855d35343 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Tue, 28 Apr 2020 12:06:45 -0400
Subject: [PATCH 09/13] Refactor CSV export slightly to make it easier to add
 new channels.

No functional change.
---
 oscar/exportcsv.cpp | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/oscar/exportcsv.cpp b/oscar/exportcsv.cpp
index 635922cc..5842cfd3 100644
--- a/oscar/exportcsv.cpp
+++ b/oscar/exportcsv.cpp
@@ -1,5 +1,6 @@
-/* ExportCSV module implementation
+/* ExportCSV module implementation
  *
+ * Copyright (c) 2020 The OSCAR Team
  * Copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net>
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -180,24 +181,16 @@ void ExportCSV::on_exportButton_clicked()
     countlist.append(CPAP_UserFlag2);
     countlist.append(CPAP_PressurePulse);
 
-    avglist.append(CPAP_Pressure);
-    avglist.append(CPAP_IPAP);
-    avglist.append(CPAP_EPAP);
-    avglist.append(CPAP_FLG);        // Pholynyk, 25Aug2015, add ResMed Flow Limitation
+    QVector<ChannelID> statChannels = { CPAP_Pressure, CPAP_IPAP, CPAP_EPAP, CPAP_FLG };
+    for (auto & chan : statChannels) {
+        avglist.append(chan);
+        p90list.append(chan);
+        maxlist.append(chan);
+    }
 
-    p90list.append(CPAP_Pressure);
-    p90list.append(CPAP_IPAP);
-    p90list.append(CPAP_EPAP);
-    p90list.append(CPAP_FLG);
-       
     float percentile=p_profile->general->prefCalcPercentile()/100.0;                   // Pholynyk, 18Aug2015
     EventDataType percent = percentile;                                                // was 0.90F
 
-    maxlist.append(CPAP_Pressure);    // Pholynyk, 18Aug2015, add maximums
-    maxlist.append(CPAP_IPAP);
-    maxlist.append(CPAP_EPAP);
-    maxlist.append(CPAP_FLG);
-
     // Not sure this section should be translateable.. :-/
     if (ui->rb1_details->isChecked()) {
         header = tr("DateTime") + sep + tr("Session") + sep + tr("Event") + sep + tr("Data/Duration");

From 7b65a85c144853fa2904af49ee145efa3c3aa0bc Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Tue, 28 Apr 2020 12:11:41 -0400
Subject: [PATCH 10/13] Add PRS1 pressure-set channels to CSV export.

---
 Htmldocs/release_notes.html | 1 +
 oscar/exportcsv.cpp         | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Htmldocs/release_notes.html b/Htmldocs/release_notes.html
index b35375ed..83b4b468 100644
--- a/Htmldocs/release_notes.html
+++ b/Htmldocs/release_notes.html
@@ -23,6 +23,7 @@
       <li>[new] Automatically detect and resolve graphics-related crashes on Windows.</li>
       <li>[new] Support AVAPS in the Overview pressure chart.</li>
       <li>[fix] Fix missing bars in the Overview pressure chart for Philips Respironics devices.</li>
+      <li>[fix] Add missing Philips Respironics pressure channels to CSV export.</li>
       <li>[fix] Add support for the Bi-Flex lock setting on pre-DreamStation ventilators.</li>
       <li>[fix] Fix the pressure waveform scale for the BiPAP autoSV Advanced 30 (960T)</li>
       <li>[fix] Add support for rise time mode on DreamStation BiPAP devices (600X-700X).</li>
diff --git a/oscar/exportcsv.cpp b/oscar/exportcsv.cpp
index 5842cfd3..4c5e6a32 100644
--- a/oscar/exportcsv.cpp
+++ b/oscar/exportcsv.cpp
@@ -181,7 +181,7 @@ void ExportCSV::on_exportButton_clicked()
     countlist.append(CPAP_UserFlag2);
     countlist.append(CPAP_PressurePulse);
 
-    QVector<ChannelID> statChannels = { CPAP_Pressure, CPAP_IPAP, CPAP_EPAP, CPAP_FLG };
+    QVector<ChannelID> statChannels = { CPAP_Pressure, CPAP_PressureSet, CPAP_IPAP, CPAP_IPAPSet, CPAP_EPAP, CPAP_EPAPSet, CPAP_FLG };
     for (auto & chan : statChannels) {
         avglist.append(chan);
         p90list.append(chan);

From 6261752022049ba5ad2a35ed18ea6b1dea1e5e44 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Tue, 28 Apr 2020 13:00:58 -0400
Subject: [PATCH 11/13] Fix zero AHI in CSV session export when there are
 multiple slices.

This only affected PRS1, and it seems like the other places where
the broken Session::hours() result was used were:

- GT_SESSIONS, which seems to be unused
- settings_wavg, where it had no effect

The other uses of Settings::hours() were where there was only
a single slice, in which case it returned the right result:

- gSessionTimesChar::paint (the one still in use)
- Icon loader
- Resmed loader
---
 Htmldocs/release_notes.html | 1 +
 oscar/SleepLib/session.h    | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Htmldocs/release_notes.html b/Htmldocs/release_notes.html
index 83b4b468..24050842 100644
--- a/Htmldocs/release_notes.html
+++ b/Htmldocs/release_notes.html
@@ -24,6 +24,7 @@
       <li>[new] Support AVAPS in the Overview pressure chart.</li>
       <li>[fix] Fix missing bars in the Overview pressure chart for Philips Respironics devices.</li>
       <li>[fix] Add missing Philips Respironics pressure channels to CSV export.</li>
+      <li>[fix] Fix zero Philips Respironics AHI in CSV session export.</li>
       <li>[fix] Add support for the Bi-Flex lock setting on pre-DreamStation ventilators.</li>
       <li>[fix] Fix the pressure waveform scale for the BiPAP autoSV Advanced 30 (960T)</li>
       <li>[fix] Add support for rise time mode on DreamStation BiPAP devices (600X-700X).</li>
diff --git a/oscar/SleepLib/session.h b/oscar/SleepLib/session.h
index 80a167a5..4350dbdc 100644
--- a/oscar/SleepLib/session.h
+++ b/oscar/SleepLib/session.h
@@ -194,6 +194,7 @@ class Session
                     t += slice.end - slice.start;
                 }
             }
+            t = t / 3600000.0;
         }
         return t;
     }

From 5f0960aa4d2a371dfdd6b6ee8578687b4a0df1ed Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Wed, 29 Apr 2020 10:22:12 -0400
Subject: [PATCH 12/13] Add support for PRS1 sessions with oximetry data split
 between files.

---
 oscar/SleepLib/loader_plugins/prs1_loader.cpp | 60 ++++++++++---------
 oscar/SleepLib/loader_plugins/prs1_loader.h   |  6 +-
 2 files changed, 34 insertions(+), 32 deletions(-)

diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp
index 61488972..e2f3672a 100644
--- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp
+++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp
@@ -982,12 +982,9 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin
                     // All samples exhibiting this behavior are DreamStations.
                     task->m_wavefiles.append(fi.canonicalFilePath());
                 } else if (ext == 6) {
-                    if (!task->oxifile.isEmpty()) {
-                        qDebug() << sid << "already has oximetry file" << relativePath(task->oxifile)
-                            << "skipping" << relativePath(fi.canonicalFilePath());
-                        continue;
-                    }
-                    task->oxifile = fi.canonicalFilePath();
+                    // Oximetry data can also be split into multiple files, see waveform
+                    // comment above.
+                    task->m_oxifiles.append(fi.canonicalFilePath());
                 }
 
                 continue;
@@ -8413,7 +8410,7 @@ bool PRS1Import::ParseSession(void)
         
         // If are no mask-on slices, then there's not any meaningful event or waveform data for the session.
         // If there's no no event or waveform data, mark this session as a summary.
-        if (session->m_slices.count() == 0 || (m_event_chunks.count() == 0 && m_wavefiles.isEmpty() && oxifile.isEmpty())) {
+        if (session->m_slices.count() == 0 || (m_event_chunks.count() == 0 && m_wavefiles.isEmpty() && m_oxifiles.isEmpty())) {
             session->setSummaryOnly(true);
             save = true;
             break;  // and skip the occasional fragmentary event or waveform data
@@ -8430,13 +8427,26 @@ bool PRS1Import::ParseSession(void)
 
         if (!m_wavefiles.isEmpty()) {
             // Parse .005 Waveform files
-            ImportWaveforms();
+            waveforms = ReadWaveformData(m_wavefiles, "Waveform");
+
+            if (session->eventlist.contains(CPAP_FlowRate)) {
+                if (waveforms.size() > 0) {
+                    // Delete anything called "Flow rate" picked up in the events file if high-resolution data is present
+                    // TODO: Is this still used anywhere?
+                    qWarning() << session->session() << "Deleting flow rate events due to flow rate waveform data";
+                    session->destroyEvent(CPAP_FlowRate);
+                }
+            }
+
+            // Extract raw data into channels.
+            ParseWaveforms();
         }
 
-        if (!oxifile.isEmpty()) {
-            // Parse .006 Waveform file
-            oximetry = loader->ParseFile(oxifile);
-            oximetry = CoalesceWaveformChunks(oximetry);
+        if (!m_oxifiles.isEmpty()) {
+            // Parse .006 Waveform files
+            oximetry = ReadWaveformData(m_oxifiles, "Oximetry");
+
+            // Extract raw data into channels.
             ParseOximetry();
         }
 
@@ -8447,16 +8457,17 @@ bool PRS1Import::ParseSession(void)
 }
 
 
-void PRS1Import::ImportWaveforms()
+QList<PRS1DataChunk *> PRS1Import::ReadWaveformData(QList<QString> & files, const char* label)
 {
     QMap<qint64,PRS1DataChunk *> waveform_chunks;
+    QList<PRS1DataChunk *> result;
 
-    if (m_wavefiles.count() > 1) {
-        qDebug() << session->session() << "Waveform data split across multiple files";
+    if (files.count() > 1) {
+        qDebug() << session->session() << label << "data split across multiple files";
     }
     
-    for (auto & f : m_wavefiles) {
-        // Parse a single .005 Waveform file
+    for (auto & f : files) {
+        // Parse a single .005 or .006 waveform file
         QList<PRS1DataChunk *> file_chunks = loader->ParseFile(f);
         for (auto & chunk : file_chunks) {
             PRS1DataChunk* previous = waveform_chunks[chunk->timestamp];
@@ -8471,21 +8482,12 @@ void PRS1Import::ImportWaveforms()
     }
     
     // Get the list of pointers sorted by timestamp.
-    waveforms = waveform_chunks.values();
+    result = waveform_chunks.values();
 
     // Coalesce contiguous waveform chunks into larger chunks.
-    waveforms = CoalesceWaveformChunks(waveforms);
+    result = CoalesceWaveformChunks(result);
 
-    if (session->eventlist.contains(CPAP_FlowRate)) {
-        if (waveforms.size() > 0) {
-            // Delete anything called "Flow rate" picked up in the events file if real data is present
-            qWarning() << session->session() << "Deleting flow rate events due to flow rate waveform data";
-            session->destroyEvent(CPAP_FlowRate);
-        }
-    }
-
-    // Extract raw data into channels.
-    ParseWaveforms();
+    return result;
 }
 
 
diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.h b/oscar/SleepLib/loader_plugins/prs1_loader.h
index f6469895..c7270010 100644
--- a/oscar/SleepLib/loader_plugins/prs1_loader.h
+++ b/oscar/SleepLib/loader_plugins/prs1_loader.h
@@ -295,7 +295,7 @@ public:
 
 
     QList<QString> m_wavefiles;
-    QString oxifile;
+    QList<QString> m_oxifiles;
 
     //! \brief Imports .000 files for bricks.
     bool ImportCompliance();
@@ -306,8 +306,8 @@ public:
     //! \brief Imports the .002 event file(s).
     bool ImportEvents();
 
-    //! \brief Imports the .005 event file(s).
-    void ImportWaveforms();
+    //! \brief Reads the .005 or .006 waveform file(s).
+    QList<PRS1DataChunk *> ReadWaveformData(QList<QString> & files, const char* label);
 
     //! \brief Coalesce contiguous .005 or .006 waveform chunks from the file into larger chunks for import.
     QList<PRS1DataChunk *> CoalesceWaveformChunks(QList<PRS1DataChunk *> & allchunks);

From 01c7f7cdc00e5505f380bc4615be57a347d66dc8 Mon Sep 17 00:00:00 2001
From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com>
Date: Wed, 29 Apr 2020 10:40:23 -0400
Subject: [PATCH 13/13] Exclude additional invalid samples in PRS1 oximetry.

Also clean up some function names and remove unnecessary code.
---
 Htmldocs/release_notes.html                   |  1 +
 oscar/SleepLib/loader_plugins/prs1_loader.cpp | 27 +++++++------------
 oscar/SleepLib/loader_plugins/prs1_loader.h   |  4 +--
 3 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/Htmldocs/release_notes.html b/Htmldocs/release_notes.html
index 24050842..4ccde935 100644
--- a/Htmldocs/release_notes.html
+++ b/Htmldocs/release_notes.html
@@ -29,6 +29,7 @@
       <li>[fix] Fix the pressure waveform scale for the BiPAP autoSV Advanced 30 (960T)</li>
       <li>[fix] Add support for rise time mode on DreamStation BiPAP devices (600X-700X).</li>
       <li>[fix] Remove the ramp time and pressure settings when the ramp is disabled on pre-DreamStation devices.</li>
+      <li>[fix] Improve import of Philips Respironics oximetry data.</li>
       <li>[fix] Fix occasional failure to save imported Viatom data.</li>
     </ul>
     <p>
diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp
index e2f3672a..6e9a3982 100644
--- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp
+++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp
@@ -8149,7 +8149,7 @@ QList<PRS1DataChunk *> PRS1Import::CoalesceWaveformChunks(QList<PRS1DataChunk *>
 }
 
 
-void PRS1Import::ParseOximetry()
+void PRS1Import::ImportOximetry()
 {
     int size = oximetry.size();
 
@@ -8205,10 +8205,10 @@ void PRS1Import::ImportOximetryChannel(ChannelID channel, QByteArray & data, qui
     quint64 start_ti;
     int start_i;
     
-    // Split eventlist on invalid values (255)
+    // Split eventlist on invalid values (254-255)
     for (int i=0; i < data.size(); i++) {
         unsigned char value = raw[i];
-        bool valid = (value != 255);
+        bool valid = (value < 254);
 
         if (valid) {
             if (pending_samples == false) {
@@ -8218,7 +8218,7 @@ void PRS1Import::ImportOximetryChannel(ChannelID channel, QByteArray & data, qui
             }
             
             if (channel == OXI_Pulse) {
-                if (value > 200) UNEXPECTED_VALUE(value, "<= 200 bpm");
+                if (value > 240) UNEXPECTED_VALUE(value, "<= 240 bpm");
             } else {
                 if (value > 100) UNEXPECTED_VALUE(value, "<= 100%");
             }
@@ -8242,7 +8242,7 @@ void PRS1Import::ImportOximetryChannel(ChannelID channel, QByteArray & data, qui
 }
 
 
-void PRS1Import::ParseWaveforms()
+void PRS1Import::ImportWaveforms()
 {
     int size = waveforms.size();
     quint64 s1, s2;
@@ -8429,25 +8429,16 @@ bool PRS1Import::ParseSession(void)
             // Parse .005 Waveform files
             waveforms = ReadWaveformData(m_wavefiles, "Waveform");
 
-            if (session->eventlist.contains(CPAP_FlowRate)) {
-                if (waveforms.size() > 0) {
-                    // Delete anything called "Flow rate" picked up in the events file if high-resolution data is present
-                    // TODO: Is this still used anywhere?
-                    qWarning() << session->session() << "Deleting flow rate events due to flow rate waveform data";
-                    session->destroyEvent(CPAP_FlowRate);
-                }
-            }
-
-            // Extract raw data into channels.
-            ParseWaveforms();
+            // Extract and import raw data into channels.
+            ImportWaveforms();
         }
 
         if (!m_oxifiles.isEmpty()) {
             // Parse .006 Waveform files
             oximetry = ReadWaveformData(m_oxifiles, "Oximetry");
 
-            // Extract raw data into channels.
-            ParseOximetry();
+            // Extract and import raw data into channels.
+            ImportOximetry();
         }
 
         save = true;
diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.h b/oscar/SleepLib/loader_plugins/prs1_loader.h
index c7270010..d44d7f4a 100644
--- a/oscar/SleepLib/loader_plugins/prs1_loader.h
+++ b/oscar/SleepLib/loader_plugins/prs1_loader.h
@@ -313,10 +313,10 @@ public:
     QList<PRS1DataChunk *> CoalesceWaveformChunks(QList<PRS1DataChunk *> & allchunks);
 
     //! \brief Takes the parsed list of Flow/MaskPressure waveform chunks and adds them to the database
-    void ParseWaveforms();
+    void ImportWaveforms();
 
     //! \brief Takes the parsed list of oximeter waveform chunks and adds them to the database.
-    void ParseOximetry();
+    void ImportOximetry();
 
     //! \brief Adds a single channel of continuous oximetry data to the database, splitting on any missing samples.
     void ImportOximetryChannel(ChannelID channel, QByteArray & data, quint64 ti, qint64 dur);