From b678b137e52b606904803f1a5a4a3c684fb24cdd Mon Sep 17 00:00:00 2001
From: LoudSnorer <Just4Me.1947@gmail.com>
Date: Tue, 13 Jun 2023 12:32:51 -0400
Subject: [PATCH] statistics: allow user to select report date.

---
 oscar/SleepLib/profiles.h |   8 +-
 oscar/mainwindow.cpp      | 210 ++++++++++++++++++--------------------
 oscar/mainwindow.h        |   2 +
 oscar/mainwindow.ui       | 163 +++++++++++++++++++++++++----
 oscar/statistics.cpp      |  72 ++++++-------
 oscar/statistics.h        |   2 +
 6 files changed, 285 insertions(+), 172 deletions(-)

diff --git a/oscar/SleepLib/profiles.h b/oscar/SleepLib/profiles.h
index e5caa617..3ab3b29c 100644
--- a/oscar/SleepLib/profiles.h
+++ b/oscar/SleepLib/profiles.h
@@ -368,6 +368,7 @@ const QString STR_US_PrefCalcPercentile = "PrefCalcPercentile";
 const QString STR_US_PrefCalcMax = "PrefCalcMax";
 const QString STR_US_ShowUnknownFlags = "ShowUnknownFlags";
 const QString STR_US_StatReportMode = "StatReportMode";
+const QString STR_US_StatReportStart = "StatReportStart";
 const QString STR_US_StatReportRangeStart = "StatReportRangeStart";
 const QString STR_US_StatReportRangeEnd = "StatReportRangeEnd";
 const QString STR_US_LastOverviewRange = "LastOverviewRange";
@@ -486,11 +487,11 @@ class OxiSettings : public PrefSettings
     {
 
         // Intialized non-user changable item - set during import of data?
-        initPref(STR_OS_EnableOximetry, false); 
+        initPref(STR_OS_EnableOximetry, false);
         initPref(STR_OS_DefaultDevice, QString());
         initPref(STR_OS_SyncOximeterClock, true);
         initPref(STR_OS_OximeterType, 0);
-        initPref(STR_OS_SkipOxiIntroScreen, false); 
+        initPref(STR_OS_SkipOxiIntroScreen, false);
 
         // Initialize Changeable via GUI parameters with default values
         initPref(STR_OS_SPO2DropDuration, defaultValue_OS_SPO2DropDuration);
@@ -760,6 +761,7 @@ class UserSettings : public PrefSettings
         m_prefCalcPercentile = initPref(STR_US_PrefCalcPercentile, (double)95.0).toDouble();
         m_prefCalcMax = initPref(STR_US_PrefCalcMax, (int)0).toInt();
         initPref(STR_US_StatReportMode, 0);
+        initPref(STR_US_StatReportStart, QDate(1,1,2000));
         initPref(STR_US_StatReportRangeStart, QDate(1,1,2000));
         initPref(STR_US_StatReportRangeEnd, QDate(1,1,2000));
         m_showUnownFlags = initPref(STR_US_ShowUnknownFlags, false).toBool();
@@ -775,6 +777,7 @@ class UserSettings : public PrefSettings
     inline double prefCalcPercentile() const { return m_prefCalcPercentile; }
     inline int prefCalcMax() const { return m_prefCalcMax; }
     int statReportMode() const { return getPref(STR_US_StatReportMode).toInt(); }
+    QDate statReportStart() const { return getPref(STR_US_StatReportStart).toDate(); }
     QDate statReportRangeStart() const { return getPref(STR_US_StatReportRangeStart).toDate(); }
     QDate statReportRangeEnd() const { return getPref(STR_US_StatReportRangeEnd).toDate(); }
     inline bool showUnknownFlags() const { return m_showUnownFlags; }
@@ -791,6 +794,7 @@ class UserSettings : public PrefSettings
     void setPrefCalcPercentile(double p) { setPref(STR_US_PrefCalcPercentile, m_prefCalcPercentile=p); }
     void setPrefCalcMax(int i) { setPref(STR_US_PrefCalcMax, m_prefCalcMax=i); }
     void setStatReportMode(int i) { setPref(STR_US_StatReportMode, i); }
+    void setStatReportStart(QDate i) { setPref(STR_US_StatReportStart, i); }
     void setStatReportRangeStart(QDate i) { setPref (STR_US_StatReportRangeStart, i); }
     void setStatReportRangeEnd(QDate i) { setPref (STR_US_StatReportRangeEnd, i); }
     void setShowUnknownFlags(bool b) { setPref(STR_US_ShowUnknownFlags, m_showUnownFlags=b); }
diff --git a/oscar/mainwindow.cpp b/oscar/mainwindow.cpp
index 7b609ac6..88288b7e 100644
--- a/oscar/mainwindow.cpp
+++ b/oscar/mainwindow.cpp
@@ -117,7 +117,7 @@ MainWindow::MainWindow(QWidget *parent) :
 //        systraymenu->addAction(tr("Check for &Updates"), this, SLOT(on_actionCheck_for_Updates_triggered()));
         systraymenu->addSeparator();
         systraymenu->addAction(tr("E&xit"), this, SLOT(close()));
-        
+
 //      systraymenu = nullptr;
     } else { // if not available, the messages will popup in the taskbar
         qDebug() << "No System Tray menues";
@@ -190,37 +190,6 @@ void MainWindow::SetupGUI()
     ui->statEndDate->calendarWidget()->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
     ui->statEndDate->calendarWidget()->setFirstDayOfWeek(dow);
 
-    ui->statEndDate->setVisible(false);
-    ui->statStartDate->setVisible(false);
-
-//    ui->reportModeRange->setVisible(false);
-    int srm = 0;
-    if (p_profile) {
-        srm = p_profile->general->statReportMode();
-    }
-
-    switch(srm) {
-        case 0:
-            ui->reportModeStandard->setChecked(true);
-            break;
-        case 1:
-            ui->reportModeMonthly->setChecked(true);
-            break;
-        case 2:
-            ui->reportModeRange->setChecked(true);
-            ui->statEndDate->setVisible(true);
-            ui->statStartDate->setVisible(true);
-            break;
-        default:
-            if (p_profile) {
-                p_profile->general->setStatReportMode(0);
-            }
-            break;
-    }
-    if (!AppSetting->showDebug()) {
-        ui->logText->hide();
-    }
-
 #ifdef Q_OS_MAC
     //p_profile->appearance->setAntiAliasing(false);
 #endif
@@ -242,7 +211,7 @@ void MainWindow::SetupGUI()
     // Navigation has offset 0
     // Bookmarks  has offset 1
     // Records    has offset 2
-    ui->toolBox->setCurrentIndex(2);    
+    ui->toolBox->setCurrentIndex(2);
     bool b = AppSetting->rightSidebarVisible();
     ui->action_Sidebar_Toggle->setChecked(b);
     ui->toolBox->setVisible(b);
@@ -287,6 +256,12 @@ void MainWindow::SetupGUI()
     ui->actionReport_a_Bug->setVisible(false);  // remove this once we actually implement it
     ui->actionExport_Review->setVisible(false);  // remove this once we actually implement it
 
+    set_reportModeStandard_mode() ;
+    if (!AppSetting->showDebug()) {
+        ui->logText->hide();
+    }
+
+
 #ifndef helpless
     help = new Help(this);
     ui->tabWidget->addTab(help, tr("Help Browser"));
@@ -414,7 +389,7 @@ void MainWindow::PopulatePurgeMenu()
         Machine *mach = machines.at(i);
         addMachineToMenu(mach, ui->menu_Rebuild_CPAP_Data);
     }
-    
+
     // Add any imported device (except the built-in journal) to the purge menu.
     machines = p_profile->GetMachines();
     for (int i=0; i < machines.size(); ++i) {
@@ -545,8 +520,7 @@ bool MainWindow::OpenProfile(QString profileName, bool skippassword)
 
     p_profile->LoadMachineData(progress);
 
-
-    if (!p_profile->LastDay(MT_CPAP).isValid() ) { // quick test if new profile or not. 
+    if (!p_profile->LastDay(MT_CPAP).isValid() ) { // quick test if new profile or not.
         // Override default value of clinicalMode if new profile.
         // Allows permissiveMode (not clinicalMode) to be the default value for existing profiles.
         p_profile->cpap->setClinicalMode(true);
@@ -561,8 +535,6 @@ bool MainWindow::OpenProfile(QString profileName, bool skippassword)
 
     QApplication::processEvents();
 
-    ui->statStartDate->setDate(p_profile->FirstDay());
-    ui->statEndDate->setDate(p_profile->LastDay());
 
     // Reload everything profile related
     if (daily) {
@@ -588,6 +560,9 @@ bool MainWindow::OpenProfile(QString profileName, bool skippassword)
 
     // Should really create welcome and statistics here, but they need redoing later anyway to kill off webkit
     ui->tabWidget->setCurrentIndex(AppSetting->openTabAtStart());
+
+    ui->statStartDate->setDate(p_profile->FirstDay());
+    ui->statEndDate->setDate(p_profile->LastDay());
     GenerateStatistics();
     PopulatePurgeMenu();
 
@@ -608,34 +583,7 @@ bool MainWindow::OpenProfile(QString profileName, bool skippassword)
     ui->tabWidget->setTabEnabled(3, !noMachines);       // overview, STR_TR_Overview);
     ui->tabWidget->setTabEnabled(4, !noMachines);       // statistics, STR_TR_Statistics);
 
-    int srm = 0;
-    if (p_profile) {
-        srm = p_profile->general->statReportMode();
-    }
-
-    switch (srm) {
-        case 0:
-            ui->reportModeStandard->setChecked(true);
-            ui->statEndDate->setVisible(false);
-            ui->statStartDate->setVisible(false);
-            break;
-        case 1:
-            ui->reportModeMonthly->setChecked(true);
-            ui->statEndDate->setVisible(false);
-            ui->statStartDate->setVisible(false);
-            break;
-        case 2:
-            ui->reportModeRange->setChecked(true);
-            ui->statEndDate->setVisible(true);
-            ui->statStartDate->setVisible(true);
-            break;
-        default:
-            if (p_profile) {
-                p_profile->general->setStatReportMode(0);
-            }
-            break;
-    }
-
+    set_reportModeStandard_mode() ;
 
     progress->close();
     delete progress;
@@ -883,14 +831,14 @@ QStringList getDriveList()
 #endif
     foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) {
         if (storage.isValid() && storage.isReady()) {
-#ifdef DEBUG_SDCARD            
+#ifdef DEBUG_SDCARD
             if (storage.fileSystemType() != "tmpfs") {      // Don't show all the Linux tmpfs mount points!
                 qDebug() << "Device:" << storage.device();
                 qDebug() << "    Path:" << storage.rootPath();
                 qDebug() << "    Name:" << storage.name();     // ...
                 qDebug() << "    FS Type:" << storage.fileSystemType();
             }
-#endif            
+#endif
             if (storage.fileSystemType() == VFAT) {
                 qDebug() << "Adding" << storage.name() << "on" << storage.rootPath() << "to drivelist";
                 drivelist.append(storage.rootPath());
@@ -918,7 +866,7 @@ QStringList getDriveList()
             drivelist.append("CROSTINI");
         }
     }
-#endif    
+#endif
     return drivelist;
 }
 
@@ -1185,7 +1133,7 @@ QList<ImportPath> MainWindow::selectCPAPDataCards(const QString & prompt, bool a
             msgBox.exec();
         }
     }
-    
+
     return datacards;
 }
 
@@ -1733,7 +1681,7 @@ void MainWindow::RestartApplication(bool force_login, QString cmdline)
 
     if (QProcess::startDetached("/usr/bin/open", args)) {
         QApplication::instance()->exit();
-    } else { 
+    } else {
         QMessageBox::warning(nullptr, STR_MessageBox_Error,
             tr("If you can read this, the restart command didn't work. You will have to do it yourself manually."), QMessageBox::Ok);
     }
@@ -1760,7 +1708,7 @@ void MainWindow::RestartApplication(bool force_login, QString cmdline)
         QApplication::instance()->exit();
 
 //        ::exit(0);
-    } else { 
+    } else {
         QMessageBox::warning(nullptr,  STR_MessageBox_Error,
             tr("If you can read this, the restart command didn't work. You will have to do it yourself manually."), QMessageBox::Ok);
     }
@@ -1983,7 +1931,7 @@ void MainWindow::on_actionPurgeMachine(QAction *action)
                                   "<font size=+2>you will lose this device's data <b>permanently</b>!</font>") + "</p>";
     }
 
-    if (QMessageBox::question(this, STR_MessageBox_Warning, 
+    if (QMessageBox::question(this, STR_MessageBox_Warning,
             "<p><b>"+STR_MessageBox_Warning+":</b> "  +
             tr("You are about to <font size=+2>obliterate</font> OSCAR's device database for the following device:</p>") +
             "<p><font size=+2>" + machname + "</font></p>" +
@@ -2046,14 +1994,14 @@ void MainWindow::purgeMachine(Machine * mach)
             tr("A file permission error caused the purge process to fail; you will have to delete the following folder manually:") +
             "\n\n" + QDir::toNativeSeparators(mach->getDataPath()), QMessageBox::Ok, QMessageBox::Ok);
 
-        if (overview) 
+        if (overview)
             overview->ReloadGraphs();
 
         if (daily) {
             daily->clearLastDay(); // otherwise Daily will crash
             daily->ReloadGraphs();
         }
-        if (welcome) 
+        if (welcome)
             welcome->refreshPage();
 
         //GenerateStatistics();
@@ -2061,7 +2009,7 @@ void MainWindow::purgeMachine(Machine * mach)
     }
 
 
-    if (overview) 
+    if (overview)
         overview->ReloadGraphs();
     QFile rxcache(p_profile->Get("{" + STR_GEN_DataFolder + "}/RXChanges.cache" ));
     rxcache.remove();
@@ -2369,7 +2317,7 @@ void MainWindow::importNonCPAP(MachineLoader &loader)
             QCoreApplication::processEvents();
         }
         QString name = loader.loaderName();
-        
+
         ImportUI importui(p_profile);
         ImportContext* ctx = new ProfileImportContext(p_profile);
         loader.SetContext(ctx);
@@ -2424,21 +2372,14 @@ void MainWindow::on_actionImport_Viatom_Data_triggered()
 
 void MainWindow::GenerateStatistics()
 {
-    QDate first = p_profile->FirstDay();
-    QDate last = p_profile->LastDay();
-    ui->statStartDate->setMinimumDate(first);
-    ui->statStartDate->setMaximumDate(last);
-
-    ui->statEndDate->setMinimumDate(first);
-    ui->statEndDate->setMaximumDate(last);
-
     Statistics stats;
     QString htmlStats = stats.GenerateHTML();
     QString htmlRecords = stats.UpdateRecordsBox();
 
-    bool brange = (p_profile->general->statReportMode() == 2);
-    ui->statEndDate->setVisible(brange);
-    ui->statStartDate->setVisible(brange);
+    set_reportModeStandard_mode() ;
+    if (!AppSetting->showDebug()) {
+        ui->logText->hide();
+    }
 
     updateFavourites();
 
@@ -2479,22 +2420,70 @@ void MainWindow::on_statisticsButton_clicked()
     }
 }
 
+void MainWindow::set_reportModeStandard_mode()
+{
+    int mode = STAT_MODE_STANDARD;
+    if (p_profile) {
+        mode = p_profile->general->statReportMode();
+
+        QDate first = p_profile->FirstDay();
+        QDate last = p_profile->LastDay();
+        ui->statStartDate->setMinimumDate(first);
+        ui->statStartDate->setMaximumDate(last);
+        ui->statEndDate->setMinimumDate(first);
+        ui->statEndDate->setMaximumDate(last);
+    }
+    switch (mode) {
+        default:
+        case STAT_MODE_STANDARD:
+            {
+            ui->reportModeStandard->setChecked(true);
+            ui->statEndDate->setVisible(true);
+            ui->statStartDate->setVisible(false);
+            ui->statEnableEndDisplay->setVisible(true);
+            if (p_profile) {
+                ui->statEndDate->setDate(p_profile->general->statReportStart());
+            }
+            }
+            break;
+        case STAT_MODE_MONTHLY:
+            ui->statStartDate->setVisible(false);
+            ui->statEndDate->setVisible(true);
+            ui->reportModeMonthly->setChecked(true);
+
+            ui->statEnableEndDisplay->setVisible(true);
+            if (p_profile) {
+                ui->statEndDate->setDate(p_profile->general->statReportStart());
+            }
+            break;
+        case STAT_MODE_RANGE:
+            ui->reportModeRange->setChecked(true);
+            ui->statStartDate->setVisible(true);
+            ui->statEndDate->setVisible(true);
+            ui->statEnableEndDisplay->setVisible(false);
+            if (p_profile) {
+                ui->statStartDate->setDate( p_profile->general->statReportRangeStart());
+                ui->statEndDate->setDate( p_profile->general->statReportRangeEnd());
+            }
+            break;
+    }
+    return;
+};
+
 void MainWindow::on_reportModeMonthly_clicked()
 {
-    ui->statStartDate->setVisible(false);
-    ui->statEndDate->setVisible(false);
-    if (p_profile->general->statReportMode() != 1) {
-        p_profile->general->setStatReportMode(1);
+    if (p_profile->general->statReportMode() != STAT_MODE_MONTHLY) {
+        p_profile->general->setStatReportMode(STAT_MODE_MONTHLY);
+        set_reportModeStandard_mode();
         GenerateStatistics();
     }
 }
 
 void MainWindow::on_reportModeStandard_clicked()
 {
-    ui->statStartDate->setVisible(false);
-    ui->statEndDate->setVisible(false);
-    if (p_profile->general->statReportMode() != 0) {
-        p_profile->general->setStatReportMode(0);
+    if (p_profile->general->statReportMode() != STAT_MODE_STANDARD) {
+        p_profile->general->setStatReportMode(STAT_MODE_STANDARD);
+        set_reportModeStandard_mode();
         GenerateStatistics();
     }
 }
@@ -2502,17 +2491,20 @@ void MainWindow::on_reportModeStandard_clicked()
 
 void MainWindow::on_reportModeRange_clicked()
 {
-    ui->statStartDate->setVisible(true);
-    ui->statEndDate->setVisible(true);
-    if (p_profile->general->statReportMode() != 2) {
-        p_profile->general->setStatReportMode(2);
+    if (p_profile->general->statReportMode() != STAT_MODE_RANGE) {
+        p_profile->general->setStatReportMode(STAT_MODE_RANGE);
+        set_reportModeStandard_mode();
         GenerateStatistics();
     }
 }
 
 void MainWindow::on_statEndDate_dateChanged(const QDate &date)
 {
-    p_profile->general->setStatReportRangeEnd(date);
+    if (p_profile->general->statReportMode() == STAT_MODE_RANGE ) {
+        p_profile->general->setStatReportRangeEnd(date);
+    } else {
+        p_profile->general->setStatReportStart(date);
+    };
     GenerateStatistics();
 }
 
@@ -2545,7 +2537,7 @@ void MainWindow::on_actionPurgeCurrentDaysOximetry_triggered()
             sess->Destroy();
             delete sess;
         }
-        
+
         // We have to update the summary cache for the affected device(s),
         // otherwise OSCAR will still think this day has oximetry data at next launch.
         for (auto & mach : machines) {
@@ -2660,12 +2652,12 @@ void MainWindow::on_actionCreate_Card_zip_triggered()
         QString cardPath = QDir(datacard.path).canonicalPath();
         QString filename;
         QString prefix;
-        
+
         // Loop until a valid folder is selected or the user cancels. Disallow the SD card itself!
         while (true) {
             // Note: macOS ignores this and points to OSCAR's most recently used directory for saving.
             QString folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
-            
+
             MachineInfo info = datacard.loader->PeekInfo(datacard.path);
             QString infostr;
             if (!info.modelnumber.isEmpty()) {
@@ -2681,7 +2673,7 @@ void MainWindow::on_actionCreate_Card_zip_triggered()
             if (filename.isEmpty()) {
                 return;  // aborted
             }
-            
+
             // Try again if the selected filename is within the SD card itself.
             QString selectedPath = QFileInfo(filename).dir().canonicalPath();
             if (selectedPath.startsWith(cardPath)) {
@@ -2698,14 +2690,14 @@ void MainWindow::on_actionCreate_Card_zip_triggered()
         if (!filename.toLower().endsWith(".zip")) {
             filename += ".zip";
         }
-        
+
         qDebug() << "Create zip of SD card:" << cardPath;
 
         ZipFile z;
         bool ok = z.Open(filename);
         if (ok) {
             ProgressDialog * prog = new ProgressDialog(this);
-            
+
             // Very full cards can sometimes take nearly a minute to scan,
             // so display the progress dialog immediately.
             prog->setMessage(tr("Calculating size..."));
@@ -2754,7 +2746,7 @@ void MainWindow::on_actionCreate_Log_zip_triggered()
     if (!filename.toLower().endsWith(".zip")) {
         filename += ".zip";
     }
-    
+
     qDebug() << "Create zip of OSCAR diagnostic logs:" << filename;
 
     ZipFile z;
@@ -2807,7 +2799,7 @@ void MainWindow::on_actionCreate_OSCAR_Data_zip_triggered()
     if (!filename.toLower().endsWith(".zip")) {
         filename += ".zip";
     }
-    
+
     qDebug() << "Create zip of OSCAR data folder:" << filename;
 
     QDir oscarData(GetAppData());
diff --git a/oscar/mainwindow.h b/oscar/mainwindow.h
index ac48807f..a5896905 100644
--- a/oscar/mainwindow.h
+++ b/oscar/mainwindow.h
@@ -318,6 +318,8 @@ class MainWindow : public QMainWindow
 
     void on_reportModeStandard_clicked();
 
+    void set_reportModeStandard_mode();
+
     void on_actionRebuildCPAP(QAction *action);
 
     void on_actionPurgeMachine(QAction *action);
diff --git a/oscar/mainwindow.ui b/oscar/mainwindow.ui
index 3aaa03a0..221e442d 100644
--- a/oscar/mainwindow.ui
+++ b/oscar/mainwindow.ui
@@ -219,6 +219,15 @@
              </color>
             </brush>
            </colorrole>
+           <colorrole role="PlaceholderText">
+            <brush brushstyle="NoBrush">
+             <color alpha="128">
+              <red>0</red>
+              <green>0</green>
+              <blue>0</blue>
+             </color>
+            </brush>
+           </colorrole>
           </active>
           <inactive>
            <colorrole role="WindowText">
@@ -347,6 +356,15 @@
              </color>
             </brush>
            </colorrole>
+           <colorrole role="PlaceholderText">
+            <brush brushstyle="NoBrush">
+             <color alpha="128">
+              <red>0</red>
+              <green>0</green>
+              <blue>0</blue>
+             </color>
+            </brush>
+           </colorrole>
           </inactive>
           <disabled>
            <colorrole role="WindowText">
@@ -475,6 +493,15 @@
              </color>
             </brush>
            </colorrole>
+           <colorrole role="PlaceholderText">
+            <brush brushstyle="NoBrush">
+             <color alpha="128">
+              <red>0</red>
+              <green>0</green>
+              <blue>0</blue>
+             </color>
+            </brush>
+           </colorrole>
           </disabled>
          </palette>
         </property>
@@ -588,16 +615,57 @@
              </item>
              <item>
               <widget class="QDateEdit" name="statStartDate">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="currentSection">
+                <enum>QDateTimeEdit::MonthSection</enum>
+               </property>
+               <property name="displayFormat">
+                <string>Qt::SystemLocaleShortDate</string>
+               </property>
                <property name="calendarPopup">
                 <bool>true</bool>
                </property>
               </widget>
              </item>
+             <item>
+              <widget class="QLabel" name="statEnableEndDisplay">
+               <property name="text">
+                <string>Report Date</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QLabel" name="statEnableEndDisplay">
+               <property name="text">
+                <string>Report Date</string>
+               </property>
+              </widget>
+             </item>
              <item>
               <widget class="QDateEdit" name="statEndDate">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="currentSection">
+                <enum>QDateTimeEdit::MonthSection</enum>
+               </property>
+               <property name="displayFormat">
+                <string>Qt::SystemLocaleShortDate</string>
+               </property>
                <property name="calendarPopup">
                 <bool>true</bool>
                </property>
+               <property name="currentSectionIndex">
+                <number>1</number>
+               </property>
               </widget>
              </item>
              <item>
@@ -605,6 +673,9 @@
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
+               <property name="sizeType">
+                <enum>QSizePolicy::MinimumExpanding</enum>
+               </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40</width>
@@ -723,8 +794,8 @@
         </font>
        </property>
        <property name="styleSheet">
-        <string notr="true">QToolBox { 
-icon-size: 24px; 
+        <string notr="true">QToolBox {
+icon-size: 24px;
 border-radius: 15px;
 background: rgb(163, 190, 255)
 }
@@ -732,7 +803,7 @@ background: rgb(163, 190, 255)
 QToolBox::tab {
     color: #444444;
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-                                stop: 0 #8181b1, 
+                                stop: 0 #8181b1,
                                 stop: 1.0 #8393c3);
  }
 
@@ -740,16 +811,16 @@ QToolBox::tab:pressed {
   font: italic;
   color: #ffffff;
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-                                stop: 0 #8181b1, 
+                                stop: 0 #8181b1,
                                 stop: 1.0 #8393c3);
 
 }
 
 QToolBox::tab:selected  {
    font: italic;
-   color: #ffffff; 
+   color: #ffffff;
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-                                stop: 0 #8181b1, 
+                                stop: 0 #8181b1,
                                 stop: 1.0 #8393c3);
 }</string>
        </property>
@@ -776,8 +847,8 @@ QToolBox::tab:selected  {
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>117</width>
-          <height>703</height>
+          <width>123</width>
+          <height>704</height>
          </rect>
         </property>
         <property name="palette">
@@ -1234,8 +1305,8 @@ border: 2px solid #56789a; border-radius: 30px;
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>132</width>
-          <height>684</height>
+          <width>137</width>
+          <height>686</height>
          </rect>
         </property>
         <property name="palette">
@@ -1504,6 +1575,15 @@ border: 2px solid #56789a; border-radius: 30px;
                 </color>
                </brush>
               </colorrole>
+              <colorrole role="PlaceholderText">
+               <brush brushstyle="NoBrush">
+                <color alpha="128">
+                 <red>0</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
              </active>
              <inactive>
               <colorrole role="WindowText">
@@ -1665,6 +1745,15 @@ border: 2px solid #56789a; border-radius: 30px;
                 </color>
                </brush>
               </colorrole>
+              <colorrole role="PlaceholderText">
+               <brush brushstyle="NoBrush">
+                <color alpha="128">
+                 <red>0</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
              </inactive>
              <disabled>
               <colorrole role="WindowText">
@@ -1826,6 +1915,15 @@ border: 2px solid #56789a; border-radius: 30px;
                 </color>
                </brush>
               </colorrole>
+              <colorrole role="PlaceholderText">
+               <brush brushstyle="NoBrush">
+                <color alpha="128">
+                 <red>0</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
              </disabled>
             </palette>
            </property>
@@ -1928,6 +2026,15 @@ border: 2px solid #56789a; border-radius: 30px;
                    </color>
                   </brush>
                  </colorrole>
+                 <colorrole role="PlaceholderText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>255</green>
+                    <blue>255</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
                 </active>
                 <inactive>
                  <colorrole role="WindowText">
@@ -1993,6 +2100,15 @@ border: 2px solid #56789a; border-radius: 30px;
                    </color>
                   </brush>
                  </colorrole>
+                 <colorrole role="PlaceholderText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>255</green>
+                    <blue>255</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
                 </inactive>
                 <disabled>
                  <colorrole role="WindowText">
@@ -2058,6 +2174,15 @@ border: 2px solid #56789a; border-radius: 30px;
                    </color>
                   </brush>
                  </colorrole>
+                 <colorrole role="PlaceholderText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>255</green>
+                    <blue>255</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
                 </disabled>
                </palette>
               </property>
@@ -2249,10 +2374,9 @@ border-radius: 10px;
            </property>
            <property name="html">
             <string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
 p, li { white-space: pre-wrap; }
-hr { height: 1px; border-width: 0; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
 &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8.25pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
            </property>
            <property name="openLinks">
@@ -2267,8 +2391,8 @@ hr { height: 1px; border-width: 0; }
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>132</width>
-          <height>684</height>
+          <width>137</width>
+          <height>686</height>
          </rect>
         </property>
         <property name="mouseTracking">
@@ -2307,10 +2431,9 @@ hr { height: 1px; border-width: 0; }
            </property>
            <property name="html">
             <string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
 p, li { white-space: pre-wrap; }
-hr { height: 1px; border-width: 0; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
 &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8.25pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
            </property>
            <property name="openLinks">
@@ -2331,7 +2454,7 @@ hr { height: 1px; border-width: 0; }
      <x>0</x>
      <y>0</y>
      <width>1023</width>
-     <height>24</height>
+     <height>22</height>
     </rect>
    </property>
    <property name="sizePolicy">
@@ -2340,8 +2463,6 @@ hr { height: 1px; border-width: 0; }
      <verstretch>0</verstretch>
     </sizepolicy>
    </property>
-
-
    <widget class="QMenu" name="menu_File">
     <property name="title">
      <string>&amp;File</string>
diff --git a/oscar/statistics.cpp b/oscar/statistics.cpp
index 4f7f8591..96f06c62 100644
--- a/oscar/statistics.cpp
+++ b/oscar/statistics.cpp
@@ -167,7 +167,12 @@ bool rxAHILessThan(const RXItem * rx1, const RXItem * rx2)
 
 void Statistics::updateDisabledInfo()
 {
-    disabledInfo.update( p_profile->LastDay(MT_CPAP), p_profile->FirstDay(MT_CPAP) );
+    QDate lastcpap = p_profile->LastGoodDay(MT_CPAP);
+    QDate firstcpap = p_profile->FirstGoodDay(MT_CPAP);
+    if (lastcpap > p_profile->general->statReportStart() ) {
+        lastcpap = p_profile->general->statReportStart();
+    }
+    disabledInfo.update( lastcpap, firstcpap );
 }
 
 void DisabledInfo::update(QDate latestDate, QDate earliestDate)
@@ -217,23 +222,6 @@ void DisabledInfo::update(QDate latestDate, QDate earliestDate)
     // convect ms to minutes
     maxDurationOfaDisabledsession/=60000 ;
     totalDurationOfDisabledSessions/=60000 ;
-    #if 0
-    DEBUGQ;
-    DEBUGQ;
-    DEBUGFW Q(p_profile->cpap->complianceHours()) ;
-    DEBUGFW Q( totalDays ) ;
-    DEBUGQ;
-    DEBUGFW Q( daysNoData ) ;
-    DEBUGFW Q( daysInCompliance ) ;
-    DEBUGFW Q( daysOutOfCompliance ) ;
-    DEBUGFW Q( numDaysDisabledSessionChangedCompliance ) ;
-    DEBUGQ;
-    DEBUGFW Q( numDisabledsessions ) ;
-    DEBUGFW Q( maxDurationOfaDisabledsession) O("minutes");
-    DEBUGFW Q( totalDurationOfDisabledSessions) O("minutes") ;
-    DEBUGFW Q( numDaysWithDisabledsessions ) ;
-    #endif
-
 };
 
 QString DisabledInfo::display(int type)
@@ -1069,6 +1057,9 @@ QString Statistics::GenerateMachineList()
 //qDebug() << "Device" << m->brand() << "series" << m->series() << "model" << m->model() << "model number" << m->modelnumber();
             QDate d1 = m->FirstDay();
             QDate d2 = m->LastDay();
+            if (d2 > p_profile->general->statReportStart() ) {
+                d2 = p_profile->general->statReportStart();
+            }
             QString mn = m->modelnumber();
             html += QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>")
                     .arg(m->brand())
@@ -1143,6 +1134,9 @@ QString Statistics::GenerateRXChanges()
     while (it.hasPrevious()) {
         it.previous();
         const RXItem & rx = it.value();
+        if (rx.start > p_profile->general->statReportStart() ) continue;
+        QDate rxend=rx.end;
+        if (rxend > p_profile->general->statReportStart() ) rxend = p_profile->general->statReportStart();
 
         QString color;
 
@@ -1161,7 +1155,7 @@ QString Statistics::GenerateRXChanges()
         html += QString("<tr %4 bgcolor='%1' onmouseover='ChangeColor(this, \"#dddddd\");' onmouseout='ChangeColor(this, \"%1\");' onclick='alert(\"overview=%2,%3\");'>")
                 .arg(color)
                 .arg(rx.start.toString(Qt::ISODate))
-                .arg(rx.end.toString(Qt::ISODate))
+                .arg(rxend.toString(Qt::ISODate))
                 .arg(datarowclass);
 
         double ahi = rdi ? (double(rx.rdi) / rx.hours) : (double(rx.ahi) /rx.hours);
@@ -1175,7 +1169,7 @@ QString Statistics::GenerateRXChanges()
                                                            .arg(rx.machine->serial());
 
         html += QString("<td>%1</td>").arg(rx.start.toString(MedDateFormat))+
-                QString("<td>%1</td>").arg(rx.end.toString(MedDateFormat))+
+                QString("<td>%1</td>").arg(rxend.toString(MedDateFormat))+
                 QString("<td>%1</td>").arg(rx.days)+
                 QString("<td>%1</td>").arg(ahi, 0, 'f', 2)+
                 QString("<td>%1</td>").arg(fli, 0, 'f', 2)+
@@ -1238,19 +1232,9 @@ QString Statistics::GenerateCPAPUsage()
     // Find first and last days with valid CPAP data
     QDate lastcpap = p_profile->LastGoodDay(MT_CPAP);
     QDate firstcpap = p_profile->FirstGoodDay(MT_CPAP);
-
-    // Get dates for standard report (last week, month, 6 months, year)
-    QDate cpapweek = lastcpap.addDays(-6);
-    QDate cpapmonth = lastcpap.addDays(-29);
-    QDate cpap6month = lastcpap.addMonths(-6);
-    QDate cpapyear = lastcpap.addMonths(-12);
-
-    // but not before the first available date of course
-    if (cpapweek   < firstcpap) { cpapweek   = firstcpap; }
-    if (cpapmonth  < firstcpap) { cpapmonth  = firstcpap; }
-    if (cpap6month < firstcpap) { cpap6month = firstcpap; }
-    if (cpapyear   < firstcpap) { cpapyear   = firstcpap; }
-
+    if (lastcpap > p_profile->general->statReportStart() ) {
+        lastcpap = p_profile->general->statReportStart();
+    }
 
     QString ahitxt = getRDIorAHIText();
 
@@ -1292,7 +1276,9 @@ QString Statistics::GenerateCPAPUsage()
         if (row.calc == SC_HEADING) {  // All sections begin with a heading
             last = p_profile->LastGoodDay(row.type);
             first = p_profile->FirstGoodDay(row.type);
-            //last = p_profile->general->statReportStart();
+            if (last > p_profile->general->statReportStart() ) {
+                last = p_profile->general->statReportStart();
+            }
 
             // Clear the periods (columns)
             periods.clear();
@@ -1332,7 +1318,7 @@ QString Statistics::GenerateCPAPUsage()
                 first = p_profile->general->statReportRangeStart();
                 last = p_profile->general->statReportRangeEnd();
                 if (first > last) {
-                    first=last;
+                    first = last;
                 }
                 periods.push_back(Period(first,last,first.toString(MedDateFormat)+" - "+last.toString(MedDateFormat)));
             }
@@ -1365,6 +1351,9 @@ QString Statistics::GenerateCPAPUsage()
         } else if (row.calc == SC_DAYS) {
             QDate first=p_profile->FirstGoodDay(row.type);
             QDate last=p_profile->LastGoodDay(row.type);
+            if (last > p_profile->general->statReportStart() ) {
+                last = p_profile->general->statReportStart();
+            }
             QString & machine = machinenames[row.type];
             int value=p_profile->countDays(row.type, first, last);
 
@@ -1541,6 +1530,9 @@ QString Statistics::UpdateRecordsBox()
     if (cpap) {
         QDate first = p_profile->FirstGoodDay(MT_CPAP);
         QDate last = p_profile->LastGoodDay(MT_CPAP);
+        if (last > p_profile->general->statReportStart() ) {
+            last = p_profile->general->statReportStart();
+        }
 
         /////////////////////////////////////////////////////////////////////////////////////
         /// Compliance and usage information
@@ -1579,7 +1571,7 @@ QString Statistics::UpdateRecordsBox()
             int baddays = 0;
 
             for (QDate date = first; date <= last; date = date.addDays(1)) {
-                Day * day = p_profile->GetGoodDay(date, MT_CPAP);
+                Day * day = p_profile->GetDay(date, MT_CPAP);
                 if (!day) continue;
 
                 float ahi = day->calcAHI();
@@ -1624,7 +1616,7 @@ QString Statistics::UpdateRecordsBox()
 
             ahilist.clear();
             for (QDate date = first; date <= last; date = date.addDays(1)) {
-                Day * day = p_profile->GetGoodDay(date, MT_CPAP);
+                Day * day = p_profile->GetDay(date, MT_CPAP);
                 if (!day) continue;
 
                 float val = 0;
@@ -1676,7 +1668,7 @@ QString Statistics::UpdateRecordsBox()
 
             ahilist.clear();
             for (QDate date = first; date <= last; date = date.addDays(1)) {
-                Day * day = p_profile->GetGoodDay(date, MT_CPAP);
+                Day * day = p_profile->GetDay(date, MT_CPAP);
                 if (!day) continue;
 
                 float leak = day->calcPON(CPAP_LargeLeak);
@@ -1714,7 +1706,7 @@ QString Statistics::UpdateRecordsBox()
             if (p_profile->hasChannel(CPAP_CSR)) {
                 ahilist.clear();
                 for (QDate date = first; date <= last; date = date.addDays(1)) {
-                    Day * day = p_profile->GetGoodDay(date, MT_CPAP);
+                    Day * day = p_profile->GetDay(date, MT_CPAP);
                     if (!day) continue;
 
                     float leak = day->calcPON(CPAP_CSR);
@@ -1744,7 +1736,7 @@ QString Statistics::UpdateRecordsBox()
             if (p_profile->hasChannel(CPAP_PB)) {
                 ahilist.clear();
                 for (QDate date = first; date <= last; date = date.addDays(1)) {
-                    Day * day = p_profile->GetGoodDay(date, MT_CPAP);
+                    Day * day = p_profile->GetDay(date, MT_CPAP);
                     if (!day) continue;
 
                     float leak = day->calcPON(CPAP_PB);
diff --git a/oscar/statistics.h b/oscar/statistics.h
index e34ababd..f4bb1fe4 100644
--- a/oscar/statistics.h
+++ b/oscar/statistics.h
@@ -38,6 +38,7 @@ private:
     int numDaysDisabledSessionChangedCompliance ;
     double maxDurationOfaDisabledsession ;
     double totalDurationOfDisabledSessions ;
+public:
     void clear () {
         totalDays = 0;
         daysNoData = 0;
@@ -237,6 +238,7 @@ class Statistics : public QObject
     QList<QDate> record_worst_ahi;
     DisabledInfo disabledInfo;
 
+
   signals:
 
   public slots: