From c3738a5b721ad38267a7ad5a03e90b67198afeda Mon Sep 17 00:00:00 2001
From: Mark Watkins <jedimark@users.sourceforge.net>
Date: Sun, 25 Dec 2011 15:05:12 +1000
Subject: [PATCH] Oximetry information cleanup, Gave graphs the ability to
 fully remove title, Print Daily Report bookmark fixes and cleanup

---
 Graphs/gGraphView.cpp |  55 ++--
 Graphs/gGraphView.h   |   8 +-
 Resources.qrc         |   1 +
 SleepLib/common.h     |   4 +
 daily.cpp             | 265 ++++++++--------
 daily.h               |   2 +-
 mainwindow.cpp        | 680 ++++++++++++++++++++++--------------------
 mainwindow.h          |   4 +
 overview.cpp          |  30 +-
 oximetry.cpp          |  11 +-
 preferencesdialog.cpp |   6 +-
 11 files changed, 559 insertions(+), 507 deletions(-)

diff --git a/Graphs/gGraphView.cpp b/Graphs/gGraphView.cpp
index df1c03dd..979e4f47 100644
--- a/Graphs/gGraphView.cpp
+++ b/Graphs/gGraphView.cpp
@@ -1019,10 +1019,6 @@ bool gGraph::isEmpty()
     return empty;
 }
 
-void gGraph::showTitle(bool b)
-{
-    m_showTitle=b;
-}
 
 float gGraph::printScaleX() { return m_graphview->printScaleX(); }
 float gGraph::printScaleY() { return m_graphview->printScaleY(); }
@@ -1073,8 +1069,8 @@ void gGraph::paint(int originX, int originY, int width, int height)
 
     int fw,font_height;
     GetTextExtent("Wg@",fw,font_height);
-    m_margintop=font_height+(8*printScaleY());
-    m_marginbottom=5;
+    if (m_margintop>0) m_margintop=font_height+(8*printScaleY());
+    //m_marginbottom=5;
 
     //glColor4f(0,0,0,1);
     left=marginLeft(),right=marginRight(),top=marginTop(),bottom=marginBottom();
@@ -1664,7 +1660,7 @@ short gGraph::marginRight() { return m_marginright; } //*m_graphview->printScale
 short gGraph::marginTop() { return m_margintop; } //*m_graphview->printScaleY(); }
 short gGraph::marginBottom() { return m_marginbottom; } //*m_graphview->printScaleY(); }
 
-QPixmap gGraph::renderPixmap(int w, int h, float scale)
+QPixmap gGraph::renderPixmap(int w, int h, bool printing)
 {
 
     gGraphView *sg=mainwin->snapshotGraph();
@@ -1678,13 +1674,17 @@ QPixmap gGraph::renderPixmap(int w, int h, float scale)
     QFont fb=*mediumfont;
     QFont fc=*bigfont;
 
-    sg->setPrintScaleX(3);
-    sg->setPrintScaleY(3);
-
-    fa.setPixelSize(30);
-    fb.setPointSize(35);
-    fc.setPointSize(80);
 
+    if (printing) {
+        fa.setPixelSize(30);
+        fb.setPixelSize(35);
+        fc.setPixelSize(80);
+        sg->setPrintScaleX(3);
+        sg->setPrintScaleY(3);
+    } else {
+        sg->setPrintScaleX(1);
+        sg->setPrintScaleY(1);
+    }
     defaultfont=&fa;
     mediumfont=&fb;
     bigfont=&fc;
@@ -2315,7 +2315,7 @@ bool gGraphView::renderGraphs()
 //    glEnd();
 //    glDisable(GL_BLEND);
 
-    float px=titleWidth-m_offsetX;
+    float px=m_offsetX;
     float py=-m_offsetY;
     int numgraphs=0;
     float h,w;
@@ -2347,7 +2347,9 @@ bool gGraphView::renderGraphs()
 
         if ((py + h + graphSpacer) >= 0) {
             w=width();
-            queGraph(m_graphs[i],px,py,width()-titleWidth,h);
+            int tw=(m_graphs[i]->showTitle() ? titleWidth : 0);
+
+            queGraph(m_graphs[i],px+tw,py,width()-tw,h);
 
             if (m_showsplitter) {
                 // draw the splitter handle
@@ -2456,10 +2458,10 @@ void gGraphView::fadeIn(bool dir)
     }
     m_inAnimation=false;
     current_day_snapshot=renderPixmap(width(),height(),false);
-    qDebug() << current_day_snapshot.depth() << "bit image depth";
-    if (current_day_snapshot.hasAlpha()){
-        qDebug() << "Snapshots are not storing alpha channel needed for texture blending";
-    }
+//    qDebug() << current_day_snapshot.depth() << "bit image depth";
+//    if (current_day_snapshot.hasAlpha()){
+//        qDebug() << "Snapshots are not storing alpha channel needed for texture blending";
+//    }
     m_inAnimation=true;
 
     m_animationStarted.start();
@@ -2941,6 +2943,21 @@ void gGraphView::keyPressEvent(QKeyEvent * event)
         event->ignore();
         return;
     }
+    if (event->key()==Qt::Key_PageUp) {
+            m_offsetY-=PROFILE.appearance->graphHeight()*3*m_scaleY;
+            m_scrollbar->setValue(m_offsetY);
+            m_offsetY=m_scrollbar->value();
+            updateGL();
+            return;
+    } else if (event->key()==Qt::Key_PageDown) {
+            m_offsetY+=PROFILE.appearance->graphHeight()*3*m_scaleY; //PROFILE.appearance->graphHeight();
+            if (m_offsetY<0) m_offsetY=0;
+            m_scrollbar->setValue(m_offsetY);
+            m_offsetY=m_scrollbar->value();
+            updateGL();
+            return;
+    //        redraw();
+    }
     gGraph *g=NULL;
     int group=0;
     // Pick the first valid graph in the primary group
diff --git a/Graphs/gGraphView.h b/Graphs/gGraphView.h
index f8726312..355dfae7 100644
--- a/Graphs/gGraphView.h
+++ b/Graphs/gGraphView.h
@@ -427,7 +427,7 @@ public:
         Note if width or height is more than the OpenGL system allows, it could result in a crash
         Keeping them under 2048 is a reasonably safe value.
         */
-    QPixmap renderPixmap(int width, int height, float fontscale=1.0);
+    QPixmap renderPixmap(int width, int height, bool printing=false);
 
     //! \brief Set Graph visibility status
     void setVisible(bool b) { m_visible=b; }
@@ -441,15 +441,17 @@ public:
     //! \brief Set the height element. (relative to the total of all heights)
     void setHeight(float height) { m_height=height; }
 
-    //! \brief Can't remember what these are for..
     int minHeight() { return m_min_height; }
     void setMinHeight(int height) { m_min_height=height; }
 
     int maxHeight() { return m_max_height; }
     void setMaxHeight(int height) { m_max_height=height; }
 
+    //! \brief Returns true if the vertical graph title is shown
+    bool showTitle() { return m_showTitle; }
+
     //! \brief Set whether or not to render the vertical graph title
-    void showTitle(bool b);
+    void setShowTitle(bool b) { m_showTitle=b; }
 
     //! \brief Returns printScaleX, used for DPI scaling in report printing
     float printScaleX();
diff --git a/Resources.qrc b/Resources.qrc
index 620f8be7..cd2cbdfc 100644
--- a/Resources.qrc
+++ b/Resources.qrc
@@ -34,5 +34,6 @@
         <file>icons/sheep.png</file>
         <file>icons/nodata.png</file>
         <file>icons/cubeoximeter.png</file>
+        <file>icons/smileyface2.png</file>
     </qresource>
 </RCC>
diff --git a/SleepLib/common.h b/SleepLib/common.h
index e0774af4..a3934c12 100644
--- a/SleepLib/common.h
+++ b/SleepLib/common.h
@@ -50,6 +50,10 @@ const QString STR_MACH_ZEO="Zeo";
 
 const QString STR_TR_BMI=QObject::tr("BMI");
 const QString STR_TR_Weight=QObject::tr("Weight");
+const QString STR_TR_PulseRate=QObject::tr("Pulse Rate");
+const QString STR_TR_SpO2=QObject::tr("SpO2");
+const QString STR_TR_Plethy=QObject::tr("Plethy");
+const QString STR_TR_FlowRate=QObject::tr("Flow Rate");
 
 const QString STR_TR_Daily=QObject::tr("Daily");
 const QString STR_TR_Overview=QObject::tr("Overview");
diff --git a/daily.cpp b/daily.cpp
index 39548051..da9b1ba5 100644
--- a/daily.cpp
+++ b/daily.cpp
@@ -113,9 +113,9 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
     TgMV=new gGraph(GraphView,tr("Tgt. Min. Vent"),schema::channel[CPAP_TgMV].description()+"\n("+schema::channel[CPAP_TgMV].units()+")",default_height);
 
     int oxigrp=PROFILE.ExistsAndTrue("SyncOximetry") ? 0 : 1;
-    PULSE=new gGraph(GraphView,tr("Pulse"),schema::channel[OXI_Pulse].description()+"\n("+schema::channel[OXI_Pulse].units()+")",default_height,oxigrp);
-    SPO2=new gGraph(GraphView,tr("SpO2"),schema::channel[OXI_SPO2].description()+"\n("+schema::channel[OXI_SPO2].units()+")",default_height,oxigrp);
-    PLETHY=new gGraph(GraphView,tr("Plethy"),schema::channel[OXI_Plethy].description()+"\n("+schema::channel[OXI_Plethy].units()+")",default_height,oxigrp);
+    PULSE=new gGraph(GraphView,STR_TR_PulseRate,schema::channel[OXI_Pulse].description()+"\n("+schema::channel[OXI_Pulse].units()+")",default_height,oxigrp);
+    SPO2=new gGraph(GraphView,STR_TR_SpO2,schema::channel[OXI_SPO2].description()+"\n("+schema::channel[OXI_SPO2].units()+")",default_height,oxigrp);
+    PLETHY=new gGraph(GraphView,STR_TR_Plethy,schema::channel[OXI_Plethy].description()+"\n("+schema::channel[OXI_Plethy].units()+")",default_height,oxigrp);
 
     // Event Pie Chart (for snapshot purposes)
     // TODO: Convert snapGV to generic for snapshotting multiple graphs (like reports does)
@@ -412,20 +412,16 @@ void Daily::UpdateEventsTree(QTreeWidget *tree,Day *day)
     tree->clear();
     if (!day) return;
 
-    //return;
     tree->setColumnCount(1); // 1 visible common.. (1 hidden)
 
-    QTreeWidgetItem *root=NULL;//new QTreeWidgetItem((QTreeWidget *)0,QStringList("Stuff"));
+    QTreeWidgetItem *root=NULL;
     QHash<ChannelID,QTreeWidgetItem *> mcroot;
     QHash<ChannelID,int> mccnt;
     int total_events=0;
-
     for (QVector<Session *>::iterator s=day->begin();s!=day->end();s++) {
 
         QHash<ChannelID,QVector<EventList *> >::iterator m;
 
-        //QTreeWidgetItem * sroot;
-
         for (m=(*s)->eventlist.begin();m!=(*s)->eventlist.end();m++) {
             ChannelID code=m.key();
             if ((code!=CPAP_Obstructive)
@@ -467,15 +463,17 @@ void Daily::UpdateEventsTree(QTreeWidget *tree,Day *day)
                 for (quint32 o=0;o<m.value()[z]->count();o++) {
                     qint64 t=m.value()[z]->time(o);
 
-                    if (code==CPAP_CSR) {
+                    if (code==CPAP_CSR) { // center it in the middle of span
                         t-=float(m.value()[z]->raw(o)/2.0)*1000.0;
                     }
                     QStringList a;
                     QDateTime d=QDateTime::fromTime_t(t/1000);
-                    QString s=QString("#%1: %2 (%3)").arg((int)++mccnt[code],(int)3,(int)10,QChar('0')).arg(d.toString("HH:mm:ss")).arg(m.value()[z]->raw(o));
+                    QString s=QString("#%1: %2 (%3)").arg((int)(++mccnt[code]),(int)3,(int)10,QChar('0')).arg(d.toString("HH:mm:ss")).arg(m.value()[z]->raw(o));
                     a.append(s);
-                    a.append(d.toString("yyyy-MM-dd HH:mm:ss"));
-                    mcr->addChild(new QTreeWidgetItem(a));
+                    QTreeWidgetItem *item=new QTreeWidgetItem(a);
+                    item->setData(0,Qt::UserRole,t);
+                    //a.append(d.toString("yyyy-MM-dd HH:mm:ss"));
+                    mcr->addChild(item);
                 }
             }
         }
@@ -566,8 +564,6 @@ void Daily::on_calendar_selectionChanged()
 void Daily::ResetGraphLayout()
 {
     GraphView->resetLayout();
-    //splitter->setSizes(splitter_sizes);
-
 }
 void Daily::graphtogglebutton_toggled(bool b)
 {
@@ -596,18 +592,17 @@ void Daily::Load(QDate date)
     }
 
     if (cpap && oxi) {
-        qint64 len=qAbs(cpap->first() - oxi->first());
-        if (len>30000) {
-            GraphView->findGraph(tr("Pulse Rate"))->setGroup(1);
-            GraphView->findGraph(tr("SpO2"))->setGroup(1);
-            GraphView->findGraph(tr("Plethy"))->setGroup(1);
+        int gr;
+
+        if (qAbs(cpap->first() - oxi->first())>30000) {
             mainwin->Notify(tr("Oximetry data exists for this day, however it's timestamps are too different, so the Graphs will not be linked."),"",3000);
-        } else {
-            //mainwin->Notify(tr("Oximetry & CPAP graphs are linked for this day"),"",2000);
-            GraphView->findGraph(tr("Pulse Rate"))->setGroup(0);
-            GraphView->findGraph(tr("SpO2"))->setGroup(0);
-            GraphView->findGraph(tr("Plethy"))->setGroup(0);
-        }
+            gr=1;
+        } else
+            gr=0;
+
+        GraphView->findGraph(STR_TR_PulseRate)->setGroup(gr);
+        GraphView->findGraph(STR_TR_SpO2)->setGroup(gr);
+        GraphView->findGraph(STR_TR_Plethy)->setGroup(gr);
     }
     lastcpapday=cpap;
 
@@ -787,6 +782,7 @@ void Daily::Load(QDate date)
                 "</table></td>";
 
             }
+            html+="</tr>";
 
 
             // Note, this may not be a problem since Qt bug 13622 was discovered
@@ -794,12 +790,16 @@ void Daily::Load(QDate date)
             // ^^ Scratch that.. pie now includes text..
 
             if (PROFILE.appearance->graphSnapshots()) {  // AHI Pie Chart
-                if (ahi+rei+fli>0) {
-                    html+="</tr>\n"; //<tr><td colspan=4 align=center><i>"+tr("Event Breakdown")+"</i></td></tr>\n";
+                if (oai+hi+cai+uai+rei+fli>0) {
+                    html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
+                    html+=QString("<tr><td colspan=4 align=center><b>%1</b></td></tr>").arg(tr("Event Breakdown"));
+                    html+="<tr><td colspan=5 align=center><hr/></td></tr>";
                     //G_AHI->setFixedSize(gwwidth,120);
                     //mainwin->snapshotGraph()->setPrintScaleX(1);
                     //mainwin->snapshotGraph()->setPrintScaleY(1);
-                    QPixmap pixmap=snapGV->renderPixmap(172,172);
+                    GAHI->setShowTitle(false);
+                    //snapGV->setFixedSize(150,150);
+                    QPixmap pixmap=GAHI->renderPixmap(150,150,false);
                     QByteArray byteArray;
                     QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
                     buffer.open(QIODevice::WriteOnly);
@@ -820,133 +820,106 @@ void Daily::Load(QDate date)
         html+="</table>";
 
     } // if (!CPAP)
-    if (!cpap && oxi) {
-        html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
-        html+="<tr><td colspan=4 align=center><b>"+oxi->machine->properties[STR_PROP_Brand]+"</b> <br>"+oxi->machine->properties[STR_PROP_Model]+"</td></tr>\n";
-        html+="<tr><td colspan=4 align=center>&nbsp;</td></tr>";
-        html+=QString("<tr><td colspan=4 align=center>SpO2 Desaturations: %1 (%2)\%</td></tr>").arg(oxi->count(OXI_SPO2Drop)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_SPO2Drop)/3600.0));
-        html+=QString("<tr><td colspan=4 align=center>Pulse Change events: %1 (%2)\%</td></tr>").arg(oxi->count(OXI_PulseChange)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_PulseChange)/3600.0));
-        html+=QString("<tr><td colspan=4 align=center>SpO2 Baseline Used: %1\%</td></tr>").arg(oxi->settings_wavg(OXI_SPO2Drop));
-        html+="</table>";
+    html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
+
+    if (oxi) {
+        html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
+        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Oximeter Information"));
+        html+="<tr><td colspan=5 align=center><hr/></td></tr>";
+        html+="<tr><td colspan=5 align=center>"+oxi->machine->properties[STR_PROP_Brand]+" "+oxi->machine->properties[STR_PROP_Model]+"</td></tr>\n";
+        html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
+        html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3)\%</td></tr>").arg(tr("SpO2 Desaturations")).arg(oxi->count(OXI_SPO2Drop)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_SPO2Drop)/3600.0));
+        html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3)\%</td></tr>").arg(tr("Pulse Change events")).arg(oxi->count(OXI_PulseChange)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_PulseChange)/3600.0));
+        html+=QString("<tr><td colspan=5 align=center>%1: %2\%</td></tr>").arg(tr("SpO2 Baseline Used")).arg(oxi->settings_wavg(OXI_SPO2Drop));
     }
     if ((cpap && !isBrick) || oxi) {
-            html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
-            if (cpap || oxi) {
-                html+="<tr height='2'><td colspan=5 height='2'><hr></td></tr>\n";
+        html+="<tr height='2'><td colspan=5>&nbsp;</td></tr>\n";
 
-                //html+=("<tr><td colspan=4 align=center>&nbsp;</td></tr>\n");
-
-                html+=("<tr><td> </td><td><b>Min</b></td><td><b>Avg</b></td><td><b>90%</b></td><td><b>Max</b></td></tr>");
-                ChannelID chans[]={
-                    CPAP_Pressure,CPAP_EPAP,CPAP_IPAP,CPAP_PS,CPAP_PTB,
-                    CPAP_MinuteVent,CPAP_AHI, CPAP_RespRate, CPAP_RespEvent,CPAP_FLG,
-                    CPAP_Leak, CPAP_LeakTotal, CPAP_Snore,CPAP_IE,CPAP_Ti,CPAP_Te, CPAP_TgMV,
-                    CPAP_TidalVolume, OXI_Pulse, OXI_SPO2
-                };
-                int numchans=sizeof(chans)/sizeof(ChannelID);
-                int suboffset=0;
-                for (int i=0;i<numchans;i++) {
-
-                    ChannelID code=chans[i];
-                    if (cpap && cpap->channelHasData(code)) {
-                        //if (code==CPAP_LeakTotal) suboffset=PROFILEIntentionalLeak"].toDouble(); else suboffset=0;
-                        QString tooltip=schema::channel[code].description();
-                        if (!schema::channel[code].units().isEmpty()) tooltip+=" ("+schema::channel[code].units()+")";
-                        html+="<tr><td align=left><a href='graph="+QString::number(code)+"' title='"+tooltip+"'>"+schema::channel[code].label()+"</a>";
-                        html+="</td><td>"+a.sprintf("%.2f",cpap->Min(code)-suboffset);
-                        html+="</td><td>"+a.sprintf("%.2f",cpap->wavg(code)-suboffset);
-                        html+="</td><td>"+a.sprintf("%.2f",cpap->p90(code)-suboffset);
-                        html+="</td><td>"+a.sprintf("%.2f",cpap->Max(code)-suboffset);
-                        html+="</td><tr>";
-                    }
-                    if (oxi && oxi->channelHasData(code)) {
-                        QString tooltip=schema::channel[code].description();
-                        if (!schema::channel[code].units().isEmpty()) tooltip+=" ("+schema::channel[code].units()+")";
-                        html+="<tr><td align=left><a href='graph="+QString::number(code)+"' title='"+tooltip+"'>"+schema::channel[code].label()+"</a>";
-                        html+="</td><td>"+a.sprintf("%.2f",oxi->Min(code));
-                        html+="</td><td>"+a.sprintf("%.2f",oxi->wavg(code));
-                        html+="</td><td>"+a.sprintf("%.2f",oxi->p90(code));
-                        html+="</td><td>"+a.sprintf("%.2f",oxi->Max(code));
-                        html+="</td><tr>";
-                    }
-                }
+        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Statistics"));
+        html+="<tr height='2'><td colspan=5><hr></td></tr>\n";
+        html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td></tr>")
+                .arg(tr("Channel"))
+                .arg(tr("Min"))
+                .arg(tr("Avg"))
+                .arg(tr("90%"))
+                .arg(tr("Max"));
+        ChannelID chans[]={
+            CPAP_Pressure,CPAP_EPAP,CPAP_IPAP,CPAP_PS,CPAP_PTB,
+            CPAP_MinuteVent,CPAP_AHI, CPAP_RespRate, CPAP_RespEvent,CPAP_FLG,
+            CPAP_Leak, CPAP_LeakTotal, CPAP_Snore,CPAP_IE,CPAP_Ti,CPAP_Te, CPAP_TgMV,
+            CPAP_TidalVolume, OXI_Pulse, OXI_SPO2
+        };
+        int numchans=sizeof(chans)/sizeof(ChannelID);
+        int suboffset=0;
+        for (int i=0;i<numchans;i++) {
 
+            ChannelID code=chans[i];
+            if (cpap && cpap->channelHasData(code)) {
+                //if (code==CPAP_LeakTotal) suboffset=PROFILEIntentionalLeak"].toDouble(); else suboffset=0;
+                QString tooltip=schema::channel[code].description();
+                if (!schema::channel[code].units().isEmpty()) tooltip+=" ("+schema::channel[code].units()+")";
+                html+=QString("<tr><td align=left>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>")
+                    .arg(QString("<a href='graph=%1' title='%2'>%3</a>")
+                        .arg(QString::number(code)).arg(tooltip).arg(schema::channel[code].label()))
+                    .arg(cpap->Min(code),0,'f',2)
+                    .arg(cpap->wavg(code),0,'f',2)
+                    .arg(cpap->p90(code),0,'f',2)
+                    .arg(cpap->Max(code),0,'f',2);
+            }
+            if (oxi && oxi->channelHasData(code)) {
+                QString tooltip=schema::channel[code].description();
+                if (!schema::channel[code].units().isEmpty()) tooltip+=" ("+schema::channel[code].units()+")";
+                html+="<tr><td align=left><a href='graph="+QString::number(code)+"' title='"+tooltip+"'>"+schema::channel[code].label()+"</a>";
+                html+="</td><td>"+a.sprintf("%.2f",oxi->Min(code));
+                html+="</td><td>"+a.sprintf("%.2f",oxi->wavg(code));
+                html+="</td><td>"+a.sprintf("%.2f",oxi->p90(code));
+                html+="</td><td>"+a.sprintf("%.2f",oxi->Max(code));
+                html+="</td><tr>";
+            }
         }
     } else {
         html+="<tr><td colspan=5 align=center><i>"+tr("No data available")+"</i></td></tr>";
         html+="<tr><td colspan=5>&nbsp;</td></tr>\n";
 
     }
-    html+="</table><hr height=2/>";
 
     if (cpap) {
-
-      //  if ((*profile)["EnableGraphSnapshots"].toBool()) {
-            /*if (cpap->channelExists(CPAP_Pressure)) {
-                html+=("<tr><td colspan=4 align=center><i>")+tr("Time@Pressure")+("</i></td></tr>\n");
-                //TAP->setFixedSize(gwwidth,30);
-                QPixmap pixmap=TAP->renderPixmap(200,30);
-                QByteArray byteArray;
-                QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
-                buffer.open(QIODevice::WriteOnly);
-                pixmap.save(&buffer, "PNG");
-                html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
-            }
-
-            if (cpap->channelExists(CPAP_EPAP)) {
-                //html+="<tr height='2'><td colspan=4 height='2'><hr></td></tr>\n";
-                html+=("<tr><td colspan=4 align=center><i>")+tr("Time@EPAP")+("</i></td></tr>\n");
-                TAP_EAP->setFixedSize(gwwidth,30);
-                QPixmap pixmap=TAP_EAP->renderPixmap(gwwidth,30,false);
-                QByteArray byteArray;
-                QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
-                buffer.open(QIODevice::WriteOnly);
-                pixmap.save(&buffer, "PNG");
-                html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
-            }
-            if (cpap->channelExists(CPAP_IPAP)) {
-                html+=("<tr><td colspan=4 align=center><i>")+tr("Time@IPAP")+("</i></td></tr>\n");
-                TAP_IAP->setFixedSize(gwwidth,30);
-                QPixmap pixmap=TAP_IAP->renderPixmap(gwwidth,30,false);
-                QByteArray byteArray;
-                QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
-                buffer.open(QIODevice::WriteOnly);
-                pixmap.save(&buffer, "PNG");
-                html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
-            } */
-        html+="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
+        html+="<tr><td colspan=5>&nbsp;</td></tr>";
+//        html+="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
+        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>").arg(tr("Machine Settings"));
+        html+="<tr><td colspan=5><hr height=2></td></tr>";
         if (cpap->machine->GetClass()==STR_MACH_PRS1) {
             int i=cpap->settings_max(PRS1_FlexMode);
             int j=cpap->settings_max(PRS1_FlexSet);
             QString flexstr=(i>1) ? schema::channel[PRS1_FlexMode].option(i)+" "+schema::channel[PRS1_FlexSet].option(j) : "None";
 
-            html+="<tr><td colspan=4>"+tr("Pressure Relief:")+" "+flexstr+"</td></tr>";
-
-            i=cpap->settings_max(PRS1_HumidSetting);
-            QString humid=(i==0) ? STR_GEN_Off : "x"+QString::number(i);
-            html+="<tr><td colspan=4>"+tr("Humidifier Setting:")+" "+humid+"</td></tr>";
+            html+=QString("<tr><td>%1</td><td colspan=4>%2</td></tr>").arg(tr("Flex"))
+                    .arg(flexstr);
+            html+=QString("<tr><td>%1</td><td colspan=4>%2</td></tr>").arg(tr("Humidifier"))
+                    .arg(cpap->settings_max(PRS1_HumidSetting) ? STR_GEN_Off : "x"+QString::number(i));
         } else if (cpap->machine->GetClass()==STR_MACH_ResMed) {
             int epr=cpap->settings_max(RMS9_EPR);
             int epr2=cpap->settings_max(RMS9_EPRSet);
-            html+="<tr><td colspan=4>"+tr("EPR Setting:")+" "+QString::number(epr)+" / "+QString::number(epr2)+"</td></tr>";
-            //epr=schema::channel[PRS1_FlexSet].optionString(pr)+QString(" x%1").arg((int)cpap->settings_max(PRS1_FlexSet));
+            html+=QString("<tr>%1</td><td colspan=4>%2 / %3</td></tr>")
+                    .arg(tr("EPR")).arg(epr).arg(epr2);
 
         }
-        html+="</table><hr height=2>";
     }
+    html+="</table>";
 
-    {
-        //}
+    if (cpap || oxi) {
         html+="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
+        html+="<tr><td colspan=4 align=center>&nbsp;</td></tr>";
+        html+=QString("<tr><td colspan=4 align=center><b>%1</b></td></tr>").arg(tr("Session Information"));
+        html+="<tr><td colspan=4 align=center><hr height=2/></td></tr>";
         QDateTime fd,ld;
         bool corrupted_waveform=false;
         QString tooltip;
-        if (cpap || oxi)
-            html+=QString("<tr><td align=left><b>%1</b></td><td align=center><b>%2</b></td><td align=center><b>%3</b></td><td align=center><b>%4</b></td></tr>")
-                    .arg(tr("SessionID"))
-                    .arg(tr("Date"))
-                    .arg(tr("Start"))
-                    .arg(tr("End"));
+        html+=QString("<tr><td align=left><b>%1</b></td><td align=center><b>%2</b></td><td align=center><b>%3</b></td><td align=center><b>%4</b></td></tr>")
+            .arg(tr("SessionID"))
+            .arg(tr("Date"))
+            .arg(tr("Start"))
+            .arg(tr("End"));
         if (cpap) {
             html+=QString("<tr><td align=left colspan=4><i>%1</i></td></tr>").arg(tr("CPAP Sessions"));
             for (QVector<Session *>::iterator s=cpap->begin();s!=cpap->end();s++) {
@@ -984,10 +957,10 @@ void Daily::Load(QDate date)
                 html+=tmp;
             }
         }
-        html+="</table>";
         if (corrupted_waveform) {
-            html+="<hr><div align=center><i>"+tr("One or more waveform record for this session had faulty source data. Some waveform overlay points may not match up correctly.")+"</i></div>";
+            html+=QString("<tr><td colspan=4 align=center><i>%1</i></td></tr>").arg(tr("One or more waveform record for this session had faulty source data. Some waveform overlay points may not match up correctly."));
         }
+        html+="</table>";
     }
     html+="</body></html>";
 
@@ -1241,12 +1214,18 @@ Session * Daily::CreateJournalSession(QDate date)
         PROFILE.AddMachine(m);
     }
     Session *sess=new Session(m,0);
-    QDateTime dt(date,QTime(17,0));
-    //dt.setDate(date);
-    //dt.setTime(QTime(17,0)); //5pm to make sure it goes in the right day
-    sess->set_first(qint64(dt.toTime_t())*1000L);
-    dt=dt.addSecs(3600);
-    sess->set_last(qint64(dt.toTime_t())*1000L);
+    qint64 st,et;
+    Day *cday=PROFILE.GetDay(date,MT_CPAP);
+    if (cday) {
+        st=cday->first();
+        et=cday->last();
+    } else {
+        QDateTime dt(date,QTime(20,0));
+        st=qint64(dt.toTime_t())*1000L;
+        et=st+3600000;
+    }
+    sess->set_first(st);
+    sess->set_last(et);
     sess->SetChanged(true);
     m->AddSession(sess,p_profile);
     return sess;
@@ -1295,21 +1274,23 @@ void Daily::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
 {
     Q_UNUSED(column);
     QDateTime d;
-    if (!item->text(1).isEmpty()) {
-        d=d.fromString(item->text(1),"yyyy-MM-dd HH:mm:ss");
-        int winsize=PROFILE.general->eventWindowSize()*60;
+    if (!item->data(0,Qt::UserRole).isNull()) {
+        qint64 winsize=qint64(PROFILE.general->eventWindowSize())*60000L;
+        qint64 t=item->data(0,Qt::UserRole).toLongLong();
+
+        double st=t-(winsize/2);
+        double et=t+(winsize/2);
+
 
-        double st=qint64((d.addSecs(-(winsize/2))).toTime_t())*1000L;
-        double et=qint64((d.addSecs(winsize/2)).toTime_t())*1000L;
         gGraph *g=GraphView->findGraph(STR_TR_EventFlags);
         if (!g) return;
         if (st<g->rmin_x) {
             st=g->rmin_x;
-            et=st+winsize*1000;
+            et=st+winsize;
         }
         if (et>g->rmax_x) {
             et=g->rmax_x;
-            st=et-winsize*1000;
+            st=et-winsize;
         }
         GraphView->SetXBounds(st,et);
     }
diff --git a/daily.h b/daily.h
index e726164d..81ce0457 100644
--- a/daily.h
+++ b/daily.h
@@ -240,7 +240,7 @@ private:
         */
     void UpdateCalendarDay(QDate date);
     /*! \fn UpdateEventsTree(QDate date)
-        \brief Refreshes the Events tree from the supplied Day object.
+        \brief Populates the Events tree from the supplied Day object.
         \param QTreeWidget * tree
         \param Day *
         */
diff --git a/mainwindow.cpp b/mainwindow.cpp
index dc0f4f55..9aa246fc 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -359,8 +359,8 @@ QString htmlHeader()
 "</style>"
 "</head>"
 "<body leftmargin=0 topmargin=0 rightmargin=0>"
-"<div align=center>"
-"<h2><img src='qrc:/docs/sheep.png' width=100px height=100px>SleepyHead v"+VersionString+" "+ReleaseStatus+"</h2>"
+"<div align=center><table cellpadding=3 cellspacing=0 border=0>"
+"<tr><td><img src='qrc:/docs/sheep.png' width=100px height=100px><td valign=center align=center><h1>SleepyHead v"+VersionString+" "+ReleaseStatus+"</h1></td></tr></table>"
 "<p><i>This page is being redesigned to be more useful... Please send me your ideas on what you'd like to see here :)</i></p>"
 "<p>The plan is to get the content happening first, then make the layout pretty...</p>"
 "</div>"
@@ -532,15 +532,15 @@ void MainWindow::on_summaryButton_clicked()
     } else {
         ahitxt=tr("AHI");
     }
+    html+="<div align=center>";
+    html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=90%>");
     if (cpapdays==0)  {
-        html+="<p>No Machine Data Imported</p>";
+        //html+="<tr><td colspan=6>No Machine Data Imported</td></tr>";
     } else {
-        html+="<div align=center>";
-        html+=QString("<p><b>Key Statistics as of %1</b></p>").arg(lastcpap.toString(Qt::SystemLocaleLongDate));
-        html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=90%>");
+        html+=QString("<tr><td colspan=6><b>CPAP Statistics as of %1</b></td></tr>").arg(lastcpap.toString(Qt::SystemLocaleLongDate));
 
         if (cpap_machines.size()>0) {
-            html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("CPAP Summary"));
+           // html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("CPAP Summary"));
 
             if (!cpapdays) {
                 html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("No CPAP data available."));
@@ -569,15 +569,14 @@ void MainWindow::on_summaryButton_clicked()
             .arg(formatTime(p_profile->calcHours(MT_CPAP,cpapyear,lastcpap)/float(cpapyeardays)));
 
             if (cpapmode<MODE_BIPAP) {
-            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-            .arg(tr("Average Pressure"))
-            .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP),0,'f',3)
-            .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapweek,lastcpap),0,'f',3)
-            .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
-            .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpap6month,lastcpap),0,'f',3)
-            .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapyear,lastcpap),0,'f',3);
-
-            if (cpapmode>MODE_CPAP) {
+                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("Average Pressure"))
+                .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP),0,'f',3)
+                .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapweek,lastcpap),0,'f',3)
+                .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
+                .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpap6month,lastcpap),0,'f',3)
+                .arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapyear,lastcpap),0,'f',3);
+            } else if (cpapmode>MODE_CPAP) {
                 html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
                 .arg(tr("95% Pressure"))
                 .arg(p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP),0,'f',3)
@@ -585,7 +584,6 @@ void MainWindow::on_summaryButton_clicked()
                 .arg(p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
                 .arg(p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP,cpap6month,lastcpap),0,'f',3)
                 .arg(p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP,cpapyear,lastcpap),0,'f',3);
-            }
             } else {
                 html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
                 .arg(tr("Min EPAP"))
@@ -633,232 +631,232 @@ void MainWindow::on_summaryButton_clicked()
             .arg(p_profile->calcPercentile(CPAP_Leak,0.5,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
             .arg(p_profile->calcPercentile(CPAP_Leak,0.5,MT_CPAP,cpap6month,lastcpap),0,'f',3)
             .arg(p_profile->calcPercentile(CPAP_Leak,0.5,MT_CPAP,cpapyear,lastcpap),0,'f',3);
-            html+="<tr><td colspan=6>What about median leak values? 90% Leaks?</td></tr>";
             html+="<tr><td colspan=6>Note, AHI calcs here are different to overview calcs.. Overview shows a average of the dialy AHI's, this shows combined counts divide by combined hours</td></tr>";
         }
-        if (oximeters.size()>0) {
-            QDate lastoxi=p_profile->LastDay(MT_OXIMETER);
-            QDate firstoxi=p_profile->FirstDay(MT_OXIMETER);
-            int days=PROFILE.countDays(MT_OXIMETER,firstcpap,lastcpap);
-            if (days>0) {
-                html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("Oximetry Summary"));
-                if (days==1) {
-                    html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 day of Oximetry Data, on %2.")).arg(days).arg(firstoxi.toString(Qt::SystemLocaleShortDate)));
-                } else {
-                    html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 days of Oximetry Data, between %2 and %3")).arg(days).arg(firstoxi.toString(Qt::SystemLocaleShortDate)).arg(lastoxi.toString(Qt::SystemLocaleShortDate)));
-                }
-
-                html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</td></tr>")
-                    .arg(tr("Details")).arg(tr("Most Recent")).arg(tr("Last 7 Days")).arg(tr("Last 30 Days")).arg(tr("Last 6 months")).arg(tr("Last Year"));
-                QDate oxiweek=lastcpap.addDays(-7);
-                QDate oximonth=lastcpap.addDays(-30);
-                QDate oxi6month=lastcpap.addMonths(-6);
-                QDate oxiyear=lastcpap.addYears(-12);
-                if (oxiweek<firstoxi) oxiweek=firstoxi;
-                if (oximonth<firstoxi) oximonth=firstoxi;
-                if (oxi6month<firstoxi) oxi6month=firstoxi;
-                if (oxiyear<firstoxi) oxiyear=firstoxi;
-                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-                    .arg(tr("Average SpO2"))
-                    .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
-                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-                    .arg(tr("Minimum SpO2"))
-                    .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
-                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-                    .arg(tr("SpO2 Events / Hour"))
-                    .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER)/p_profile->calcHours(MT_OXIMETER),0,'f',3)
-                    .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiweek,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
-                    .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oximonth,lastoxi)/p_profile->calcHours(MT_OXIMETER,oximonth,lastoxi),0,'f',3)
-                    .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxi6month,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
-                    .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiyear,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
-                html+=QString("<tr><td>%1</td><td>%2\%</td><td>%3\%</td><td>%4\%</td><td>%5\%</td><td>%6\%</td></tr>")
-                    .arg(tr("% of time in SpO2 Events"))
-                    .arg(100.0/p_profile->calcHours(MT_OXIMETER)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER)/3600.0,0,'f',3)
-                    .arg(100.0/p_profile->calcHours(MT_OXIMETER,oxiweek,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oxiweek,lastoxi)/3600.0,0,'f',3)
-                    .arg(100.0/p_profile->calcHours(MT_OXIMETER,oximonth,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oximonth,lastoxi)/3600.0,0,'f',3)
-                    .arg(100.0/p_profile->calcHours(MT_OXIMETER,oxi6month,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oxi6month,lastoxi)/3600.0,0,'f',3)
-                    .arg(100.0/p_profile->calcHours(MT_OXIMETER,oxiyear,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oxiyear,lastoxi)/3600.0,0,'f',3);
-                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-                    .arg(tr("Average Pulse Rate"))
-                    .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
-                    .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
-                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-                    .arg(tr("Minimum Pulse Rate"))
-                    .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
-                html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
-                    .arg(tr("Maximum Pulse Rate"))
-                    .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER),0,'f',3)
-                    .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
-                    .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
-            }
-        }
-
-        html+="</table>";
-        html+="</div>";
-
-        if (cpap_machines.size()>0) {
-            QDate first,last=lastcpap;
-            CPAPMode mode,cmode=MODE_UNKNOWN;
-            EventDataType cmin=0,cmax=0,min,max;
-            QDate date=lastcpap;
-            Day * day;
-            bool lastchanged;
-            int cnt=0;
-            QVector<RXChange> rxchange;
-
-            do {
-                day=PROFILE.GetDay(date,MT_CPAP);
-                lastchanged=false;
-                if (day) {
-                    mode=(CPAPMode)round(day->settings_wavg(CPAP_Mode));
-                    min=day->settings_min(CPAP_PressureMin);
-                    if (mode==MODE_CPAP) {
-                        max=day->settings_max(CPAP_PressureMin);
-                    } else max=day->settings_max(CPAP_PressureMax);
-
-                    if ((mode!=cmode) || (min!=cmin) || (max!=cmax))  {
-                        if (cmode!=MODE_UNKNOWN) {
-                            first=date.addDays(1);
-                            int days=PROFILE.countDays(MT_CPAP,first,last);
-                            RXChange rx;
-                            rx.first=first;
-                            rx.last=last;
-                            rx.days=days;
-                            rx.ahi=calcAHI(first,last);
-                            rx.mode=cmode;
-                            rx.min=cmin;
-                            rx.max=cmax;
-                            if (mode<MODE_BIPAP) {
-                                rx.per1=p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP,first,last);
-                                rx.per2=0;
-                            } else {
-                                rx.per1=p_profile->calcPercentile(CPAP_EPAP,percentile,MT_CPAP,first,last);
-                                rx.per2=p_profile->calcPercentile(CPAP_IPAP,percentile,MT_CPAP,first,last);
-                            }
-                            rx.weighted=float(rx.days)/float(cpapdays)*rx.ahi;
-                            rxchange.push_back(rx);
-                        }
-                        cmode=mode;
-                        cmin=min;
-                        cmax=max;
-                        last=date;
-                        lastchanged=true;
-                    }
-
-                }
-                date=date.addDays(-1);
-            } while (date>=firstcpap);
-            if (!lastchanged) {
-                last=date.addDays(1);
-                first=firstcpap;
-                int days=PROFILE.countDays(MT_CPAP,first,last);
-                RXChange rx;
-                rx.first=first;
-                rx.last=last;
-                rx.days=days;
-                rx.ahi=calcAHI(first,last);
-                rx.mode=mode;
-                rx.min=min;
-                rx.max=max;
-                if (mode<MODE_BIPAP) {
-                    rx.per1=p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,first,last);
-                    rx.per2=0;
-                } else {
-                    rx.per1=p_profile->calcPercentile(CPAP_EPAP,0.9,MT_CPAP,first,last);
-                    rx.per2=p_profile->calcPercentile(CPAP_IPAP,0.9,MT_CPAP,first,last);
-                }
-                rx.weighted=float(rx.days)/float(cpapdays);
-                //rx.weighted=float(days)*rx.ahi;
-                rxchange.push_back(rx);
-            }
-            QVector<RXChange *> tmpRX;
-            for (int i=0;i<rxchange.size();i++) {
-                RXChange & rx=rxchange[i];
-                if (rx.days>5)
-                    tmpRX.push_back(&rx);
-            }
-            RXsort=RX_ahi;
-            qSort(tmpRX.begin(),tmpRX.end(),RXSort);
-            tmpRX[0]->highlight=4; // worst
-            tmpRX[tmpRX.size()-1]->highlight=1; //best
-
-            // show the second best and worst..
-//            if (tmpRX.size()>4) {
-//                tmpRX[1]->highlight=3; // worst
-//                tmpRX[tmpRX.size()-2]->highlight=2; //best
-//            }
-            //RXsort=RX_first;
-            //qSort(rxchange);
-
-            html+="<div align=center>";
-            html+=QString("<br/><b>Changes to Prescription Settings</b>");
-            html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=90%>");
-            QString extratxt;
-            if (cpapmode>=MODE_BIPAP) {
-                extratxt=QString("<td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td>")
-                    .arg(tr("EPAP")).arg(tr("EPAP")).arg(tr("%1% EPAP").arg(percentile*100.0)).arg(tr("%1% IPAP").arg(percentile*100.0));
-            } else if (cpapmode>MODE_CPAP) {
-                extratxt=QString("<td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td>")
-                    .arg(tr("Min Pressure")).arg(tr("Max Pressure")).arg(tr("%1% Pressure").arg(percentile*100.0));
+    }
+    int oxisize=oximeters.size();
+    if (oxisize>0) {
+        QDate lastoxi=p_profile->LastDay(MT_OXIMETER);
+        QDate firstoxi=p_profile->FirstDay(MT_OXIMETER);
+        int days=PROFILE.countDays(MT_OXIMETER,firstoxi,lastoxi);
+        if (days>0) {
+            html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("Oximetry Summary"));
+            if (days==1) {
+                html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 day of Oximetry Data, on %2.")).arg(days).arg(firstoxi.toString(Qt::SystemLocaleShortDate)));
             } else {
-                extratxt=QString("<td><b>%1</b></td>")
-                    .arg(tr("Pressure"));
+                html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 days of Oximetry Data, between %2 and %3")).arg(days).arg(firstoxi.toString(Qt::SystemLocaleShortDate)).arg(lastoxi.toString(Qt::SystemLocaleShortDate)));
             }
-            html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td>%6</tr>")
-                      .arg(tr("First"))
-                      .arg(tr("Last"))
-                      .arg(tr("Days"))
-                      .arg(ahitxt)
-                      .arg(tr("Mode"))
-                      .arg(extratxt);
 
-            for (int i=0;i<rxchange.size();i++) {
-                RXChange rx=rxchange.at(i);
-                QString color;
-                if (rx.highlight==1) {
-                    color=" bgcolor='#c0ffc0'";
-                } else if (rx.highlight==2) {
-                    color=" bgcolor='#e0ffe0'";
-                } else if (rx.highlight==3) {
-                    color=" bgcolor='#ffe0e0'";
-                } else if (rx.highlight==4) {
-                    color=" bgcolor='#ffc0c0'";
-                } else color="";
-                if (cpapmode>=MODE_BIPAP) {
-                    extratxt=QString("<td>%1</td><td>%2</td><td>%3</td>").arg(rx.max,0,'f',2).arg(rx.per1,0,'f',2).arg(rx.per2,0,'f',2);
-                } else if (cpapmode>MODE_CPAP) {
-                    extratxt=QString("<td>%1</td><td>%2</td>").arg(rx.max,0,'f',2).arg(rx.per1,0,'f',2);
-                } else extratxt="";
-                html+=QString("<tr"+color+"><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td>%7</tr>")
-                        .arg(rx.first.toString(Qt::SystemLocaleShortDate))
-                        .arg(rx.last.toString(Qt::SystemLocaleShortDate))
-                        .arg(rx.days)
-                        .arg(rx.ahi,0,'f',2)
-                        .arg(schema::channel[CPAP_Mode].option(int(rx.mode)-1))
-                        .arg(rx.min,0,'f',2)
-                        .arg(extratxt);
-            }
-            html+="</table>";
-            html+="<i>The above has a threshold which excludes day counts less than it from the best/worst highlighting</i><br/>";
-            html+="</div>";
+            html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</td></tr>")
+                    .arg(tr("Details")).arg(tr("Most Recent")).arg(tr("Last 7 Days")).arg(tr("Last 30 Days")).arg(tr("Last 6 months")).arg(tr("Last Year"));
+            QDate oxiweek=lastoxi.addDays(-7);
+            QDate oximonth=lastoxi.addDays(-30);
+            QDate oxi6month=lastoxi.addMonths(-6);
+            QDate oxiyear=lastoxi.addYears(-12);
+            if (oxiweek<firstoxi) oxiweek=firstoxi;
+            if (oximonth<firstoxi) oximonth=firstoxi;
+            if (oxi6month<firstoxi) oxi6month=firstoxi;
+            if (oxiyear<firstoxi) oxiyear=firstoxi;
+            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("Average SpO2"))
+                .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
+            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("Minimum SpO2"))
+                .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER),0,'f',3)
+                .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
+                .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
+                .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
+                .arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
+            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("SpO2 Events / Hour"))
+                .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER)/p_profile->calcHours(MT_OXIMETER),0,'f',3)
+                .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiweek,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
+                .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oximonth,lastoxi)/p_profile->calcHours(MT_OXIMETER,oximonth,lastoxi),0,'f',3)
+                .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxi6month,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
+                .arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiyear,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
+            html+=QString("<tr><td>%1</td><td>%2\%</td><td>%3\%</td><td>%4\%</td><td>%5\%</td><td>%6\%</td></tr>")
+                .arg(tr("% of time in SpO2 Events"))
+                .arg(100.0/p_profile->calcHours(MT_OXIMETER)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER)/3600.0,0,'f',3)
+                .arg(100.0/p_profile->calcHours(MT_OXIMETER,oxiweek,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oxiweek,lastoxi)/3600.0,0,'f',3)
+                .arg(100.0/p_profile->calcHours(MT_OXIMETER,oximonth,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oximonth,lastoxi)/3600.0,0,'f',3)
+                .arg(100.0/p_profile->calcHours(MT_OXIMETER,oxi6month,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oxi6month,lastoxi)/3600.0,0,'f',3)
+                .arg(100.0/p_profile->calcHours(MT_OXIMETER,oxiyear,lastoxi)*p_profile->calcSum(OXI_SPO2Drop,MT_OXIMETER,oxiyear,lastoxi)/3600.0,0,'f',3);
+            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("Average Pulse Rate"))
+                .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
+                .arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
+            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("Minimum Pulse Rate"))
+                .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER),0,'f',3)
+                .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
+                .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
+                .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
+                .arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
+            html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
+                .arg(tr("Maximum Pulse Rate"))
+                .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER),0,'f',3)
+                .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
+                .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
+                .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
+                .arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
         }
+    }
+
+    html+="</table>";
+    html+="</div>";
+
+    if (cpapdays>0) {
+        QDate first,last=lastcpap;
+        CPAPMode mode,cmode=MODE_UNKNOWN;
+        EventDataType cmin=0,cmax=0,min,max;
+        QDate date=lastcpap;
+        Day * day;
+        bool lastchanged;
+        int cnt=0;
+        QVector<RXChange> rxchange;
+        do {
+            day=PROFILE.GetDay(date,MT_CPAP);
+            lastchanged=false;
+            if (day) {
+                mode=(CPAPMode)round(day->settings_wavg(CPAP_Mode));
+                min=day->settings_min(CPAP_PressureMin);
+                if (mode==MODE_CPAP) {
+                    max=day->settings_max(CPAP_PressureMin);
+                } else max=day->settings_max(CPAP_PressureMax);
+
+                if ((mode!=cmode) || (min!=cmin) || (max!=cmax))  {
+                    if (cmode!=MODE_UNKNOWN) {
+                        first=date.addDays(1);
+                        int days=PROFILE.countDays(MT_CPAP,first,last);
+                        RXChange rx;
+                        rx.first=first;
+                        rx.last=last;
+                        rx.days=days;
+                        rx.ahi=calcAHI(first,last);
+                        rx.mode=cmode;
+                        rx.min=cmin;
+                        rx.max=cmax;
+                        if (mode<MODE_BIPAP) {
+                            rx.per1=p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP,first,last);
+                            rx.per2=0;
+                        } else {
+                            rx.per1=p_profile->calcPercentile(CPAP_EPAP,percentile,MT_CPAP,first,last);
+                            rx.per2=p_profile->calcPercentile(CPAP_IPAP,percentile,MT_CPAP,first,last);
+                        }
+                        rx.weighted=float(rx.days)/float(cpapdays)*rx.ahi;
+                        rxchange.push_back(rx);
+                    }
+                    cmode=mode;
+                    cmin=min;
+                    cmax=max;
+                    last=date;
+                    lastchanged=true;
+                }
+
+            }
+            date=date.addDays(-1);
+        } while (date>=firstcpap);
+
+        if (!lastchanged) {
+            last=date.addDays(1);
+            first=firstcpap;
+            int days=PROFILE.countDays(MT_CPAP,first,last);
+            RXChange rx;
+            rx.first=first;
+            rx.last=last;
+            rx.days=days;
+            rx.ahi=calcAHI(first,last);
+            rx.mode=mode;
+            rx.min=min;
+            rx.max=max;
+            if (mode<MODE_BIPAP) {
+                rx.per1=p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,first,last);
+                rx.per2=0;
+            } else {
+                rx.per1=p_profile->calcPercentile(CPAP_EPAP,0.9,MT_CPAP,first,last);
+                rx.per2=p_profile->calcPercentile(CPAP_IPAP,0.9,MT_CPAP,first,last);
+            }
+            rx.weighted=float(rx.days)/float(cpapdays);
+            //rx.weighted=float(days)*rx.ahi;
+            rxchange.push_back(rx);
+        }
+
+        QVector<RXChange *> tmpRX;
+        for (int i=0;i<rxchange.size();i++) {
+            RXChange & rx=rxchange[i];
+            if (rx.days>5)
+                tmpRX.push_back(&rx);
+        }
+        RXsort=RX_ahi;
+        qSort(tmpRX.begin(),tmpRX.end(),RXSort);
+        tmpRX[0]->highlight=4; // worst
+        tmpRX[tmpRX.size()-1]->highlight=1; //best
+
+        //show the second best and worst..
+        //if (tmpRX.size()>4) {
+        //                tmpRX[1]->highlight=3; // worst
+        //                tmpRX[tmpRX.size()-2]->highlight=2; //best
+        //            }
+        //RXsort=RX_first;
+        //qSort(rxchange);
+        html+="<div align=center>";
+        html+=QString("<br/><b>Changes to Prescription Settings</b>");
+        html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=90%>");
+        QString extratxt;
+        if (cpapmode>=MODE_BIPAP) {
+            extratxt=QString("<td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td>")
+                .arg(tr("EPAP")).arg(tr("EPAP")).arg(tr("%1% EPAP").arg(percentile*100.0)).arg(tr("%1% IPAP").arg(percentile*100.0));
+        } else if (cpapmode>MODE_CPAP) {
+            extratxt=QString("<td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td>")
+                .arg(tr("Min Pressure")).arg(tr("Max Pressure")).arg(tr("%1% Pressure").arg(percentile*100.0));
+        } else {
+            extratxt=QString("<td><b>%1</b></td>")
+                .arg(tr("Pressure"));
+        }
+        html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td>%6</tr>")
+                  .arg(tr("First"))
+                  .arg(tr("Last"))
+                  .arg(tr("Days"))
+                  .arg(ahitxt)
+                  .arg(tr("Mode"))
+                  .arg(extratxt);
+
+        for (int i=0;i<rxchange.size();i++) {
+            RXChange rx=rxchange.at(i);
+            QString color;
+            if (rx.highlight==1) {
+                color=" bgcolor='#c0ffc0'";
+            } else if (rx.highlight==2) {
+                color=" bgcolor='#e0ffe0'";
+            } else if (rx.highlight==3) {
+                color=" bgcolor='#ffe0e0'";
+            } else if (rx.highlight==4) {
+                color=" bgcolor='#ffc0c0'";
+            } else color="";
+            if (cpapmode>=MODE_BIPAP) {
+                extratxt=QString("<td>%1</td><td>%2</td><td>%3</td>").arg(rx.max,0,'f',2).arg(rx.per1,0,'f',2).arg(rx.per2,0,'f',2);
+            } else if (cpapmode>MODE_CPAP) {
+                extratxt=QString("<td>%1</td><td>%2</td>").arg(rx.max,0,'f',2).arg(rx.per1,0,'f',2);
+            } else extratxt="";
+            html+=QString("<tr"+color+"><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td>%7</tr>")
+                    .arg(rx.first.toString(Qt::SystemLocaleShortDate))
+                    .arg(rx.last.toString(Qt::SystemLocaleShortDate))
+                    .arg(rx.days)
+                    .arg(rx.ahi,0,'f',2)
+                    .arg(schema::channel[CPAP_Mode].option(int(rx.mode)-1))
+                    .arg(rx.min,0,'f',2)
+                    .arg(extratxt);
+        }
+        html+="</table>";
+        html+="<i>The above has a threshold which excludes day counts less than it from the best/worst highlighting</i><br/>";
+        html+="</div>";
 
     }
     if (mach.size()>0) {
@@ -1270,10 +1268,12 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
         painter.drawText(bounds,userinfo,QTextOption(Qt::AlignLeft | Qt::AlignTop));
         if (bounds.height()>maxy) maxy=bounds.height();
     }
+    Day *cpap=NULL, *oxi=NULL;
 
     int graph_slots=0;
     if (name==STR_TR_Daily) {
-        Day *cpap=PROFILE.GetDay(date,MT_CPAP);
+        cpap=PROFILE.GetDay(date,MT_CPAP);
+        oxi=PROFILE.GetDay(date,MT_OXIMETER);
         QString cpapinfo=date.toString(Qt::SystemLocaleLongDate)+"\n\n";
         if (cpap) {
             time_t f=cpap->first()/1000L;
@@ -1317,22 +1317,11 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
             float lki=cpap->count(CPAP_LeakFlag)/cpap->hours();
             float exp=cpap->count(CPAP_ExP)/cpap->hours();
 
-            int piesize=(2048.0/8.0)*1.4;   // 1.5" in size
+            int piesize=(2048.0/8.0)*1.3;   // 1.5" in size
             //float fscale=font_scale;
             //if (!highres)
 //                fscale=1;
 
-            getDaily()->eventBreakdownPie()->showTitle(false);
-            getDaily()->eventBreakdownPie()->setMargins(0,0,0,0);
-            QPixmap ebp;
-            if (ahi>0) {
-                ebp=getDaily()->eventBreakdownPie()->renderPixmap(piesize,piesize,1);
-            } else {
-                ebp=QPixmap::fromImage(*images["smiley"]);
-            }
-            painter.drawPixmap(virt_width-piesize,bounds.height()/2,piesize,piesize,ebp);
-            getDaily()->eventBreakdownPie()->showTitle(true);
-
             QString stats;
             painter.setFont(medium_font);
             if (PROFILE.general->calculateRDI())
@@ -1342,6 +1331,18 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
             QRectF bounds=painter.boundingRect(QRectF(0,0,virt_width,0),stats,QTextOption(Qt::AlignRight));
             painter.drawText(bounds,stats,QTextOption(Qt::AlignRight));
 
+
+            getDaily()->eventBreakdownPie()->setShowTitle(false);
+            getDaily()->eventBreakdownPie()->setMargins(0,0,0,0);
+            QPixmap ebp;
+            if (ahi>0) {
+                ebp=getDaily()->eventBreakdownPie()->renderPixmap(piesize,piesize,true);
+            } else {
+                ebp=QPixmap(":/icons/smileyface.png");
+            }
+            painter.drawPixmap(virt_width-piesize,bounds.height(),piesize,piesize,ebp);
+            getDaily()->eventBreakdownPie()->setShowTitle(true);
+
             cpapinfo+="\n\n";
 
             painter.setFont(report_font);
@@ -1396,88 +1397,114 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
     QStringList labels;
     QVector<gGraph *> graphs;
     QVector<qint64> start,end;
-    qint64 st,et;
-    gv->GetXBounds(st,et);
+    qint64 savest,saveet;
+    gv->GetXBounds(savest,saveet);
+    qint64 st=savest,et=saveet;
+
     gGraph *g;
-    if (!print_bookmarks) {
+    if (name==STR_TR_Daily) {
+        if (!print_bookmarks) {
+            for (int i=0;i<gv->size();i++) {
+                gGraph *g=(*gv)[i];
+                if (g->isEmpty()) continue;
+                if (!g->visible()) continue;
+
+                if (cpap) {
+                    st=cpap->first();
+                    et=cpap->last();
+                } else if (oxi) {
+                    st=oxi->first();
+                    et=oxi->last();
+                }
+
+                if (g->title()==STR_TR_FlowRate) {
+                    if (!((qAbs(savest-st)<2000) && (qAbs(saveet-et)<2000))) {
+                        start.push_back(st);
+                        end.push_back(et);
+                        graphs.push_back(g);
+                        labels.push_back(tr("Entire Day's Flow Waveform"));
+                    }
+                }
+
+                start.push_back(savest);
+                end.push_back(saveet);
+                graphs.push_back(g);
+                labels.push_back("");
+
+            }
+        } else {
+            if (journal) {
+                if (journal->settings.contains(Bookmark_Start)) {
+                    QVariantList st1=journal->settings[Bookmark_Start].toList();
+                    QVariantList et1=journal->settings[Bookmark_End].toList();
+                    QStringList notes=journal->settings[Bookmark_Notes].toStringList();
+                    gGraph *flow=gv->findGraph(STR_TR_FlowRate),
+                           *spo2=gv->findGraph(STR_TR_SpO2),
+                           *pulse=gv->findGraph(STR_TR_PulseRate);
+
+
+                    if (cpap && flow && !flow->isEmpty() && flow->visible()) {
+                        labels.push_back("Entire Day");
+                        start.push_back(cpap->first());
+                        end.push_back(cpap->last());
+                        graphs.push_back(flow);
+                    }
+                    if (oxi && spo2 && !spo2->isEmpty() && spo2->visible()) {
+                        labels.push_back("Entire Day");
+                        start.push_back(oxi->first());
+                        end.push_back(oxi->last());
+                        graphs.push_back(spo2);
+                    }
+                    if (oxi && pulse && !pulse->isEmpty() && pulse->visible()) {
+                        labels.push_back("Entire Day");
+                        start.push_back(oxi->first());
+                        end.push_back(oxi->last());
+                        graphs.push_back(pulse);
+                    }
+                    for (int i=0;i<notes.size();i++) {
+                        if (flow && !flow->isEmpty() && flow->visible()) {
+                            labels.push_back(notes.at(i));
+                            start.push_back(st1.at(i).toLongLong());
+                            end.push_back(et1.at(i).toLongLong());
+                            graphs.push_back(flow);
+                        }
+                        if (spo2 && !spo2->isEmpty() && spo2->visible()) {
+                            labels.push_back(notes.at(i));
+                            start.push_back(st1.at(i).toLongLong());
+                            end.push_back(et1.at(i).toLongLong());
+                            graphs.push_back(spo2);
+                        }
+                        if (pulse && !pulse->isEmpty() && pulse->visible()) {
+                            labels.push_back(notes.at(i));
+                            start.push_back(st1.at(i).toLongLong());
+                            end.push_back(et1.at(i).toLongLong());
+                            graphs.push_back(pulse);
+                        }
+                    }
+                }
+            }
+            for (int i=0;i<gv->size();i++) {
+                gGraph *g=(*gv)[i];
+                if (g->isEmpty()) continue;
+                if (!g->visible()) continue;
+                if ((g->title()!=STR_TR_FlowRate ) && (g->title()!=STR_TR_SpO2) && (g->title()!=STR_TR_PulseRate)) {
+                    start.push_back(st);
+                    end.push_back(et);
+                    graphs.push_back(g);
+                    labels.push_back(tr(""));
+                }
+            }
+        }
+    } else {
         for (int i=0;i<gv->size();i++) {
             gGraph *g=(*gv)[i];
             if (g->isEmpty()) continue;
             if (!g->visible()) continue;
+
             start.push_back(st);
             end.push_back(et);
             graphs.push_back(g);
-            labels.push_back("");
-            //labels.push_back(tr("Current Selection"));
-        }
-    } else {
-        if ((g=gv->findGraph(tr("Event Flags")))!=NULL) {
-            if ((!g->isEmpty()) && (g->visible())) {
-                start.push_back(st);
-                start.push_back(et);
-                graphs.push_back(g);
-                labels.push_back("");
-            }
-        }
-        if (journal) {
-            if (journal->settings.contains(Bookmark_Start)) {
-                QVariantList st1=journal->settings[Bookmark_Start].toList();
-                QVariantList et1=journal->settings[Bookmark_End].toList();
-                QStringList notes=journal->settings[Bookmark_Notes].toStringList();
-                gGraph *flow=gv->findGraph(tr("Flow Rate")),
-                       *spo2=gv->findGraph(tr("SpO2")),
-                       *pulse=gv->findGraph(tr("Pulse"));
-
-                if (flow && !flow->isEmpty() && flow->visible()) {
-                    labels.push_back("");
-                    start.push_back(st);
-                    end.push_back(et);
-                    graphs.push_back(flow);
-                }
-                if (spo2 && !spo2->isEmpty() && spo2->visible()) {
-                    labels.push_back("");
-                    start.push_back(st);
-                    end.push_back(et);
-                    graphs.push_back(spo2);
-                }
-                if (pulse && !pulse->isEmpty() && pulse->visible()) {
-                    labels.push_back("");
-                    start.push_back(st);
-                    end.push_back(et);
-                    graphs.push_back(pulse);
-                }
-                for (int i=0;i<notes.size();i++) {
-                    if (flow && !flow->isEmpty() && flow->visible()) {
-                        labels.push_back(notes.at(i));
-                        start.push_back(st1.at(i).toLongLong());
-                        end.push_back(et1.at(i).toLongLong());
-                        graphs.push_back(flow);
-                    }
-                    if (spo2 && !spo2->isEmpty() && spo2->visible()) {
-                        labels.push_back(notes.at(i));
-                        start.push_back(st1.at(i).toLongLong());
-                        end.push_back(et1.at(i).toLongLong());
-                        graphs.push_back(spo2);
-                    }
-                    if (pulse && !pulse->isEmpty() && pulse->visible()) {
-                        labels.push_back(notes.at(i));
-                        start.push_back(st1.at(i).toLongLong());
-                        end.push_back(et1.at(i).toLongLong());
-                        graphs.push_back(pulse);
-                    }
-                }
-            }
-        }
-        for (int i=0;i<gv->size();i++) {
-            gGraph *g=(*gv)[i];
-            if (g->isEmpty()) continue;
-            if (!g->visible()) continue;
-            if ((g->title()!=tr("Flow Rate")) && (g->title()!=tr("SpO2")) && (g->title()!=tr("Pulse"))) {
-                start.push_back(st);
-                end.push_back(et);
-                graphs.push_back(g);
-                labels.push_back(tr(""));
-            }
+            labels.push_back(""); // date range?
         }
     }
     int pages=ceil(float(graphs.size()+graph_slots)/float(graphs_per_page));
@@ -1552,6 +1579,7 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
         }
     }
 
+    gv->SetXBounds(savest,saveet);
     qprogress->hide();
     painter.end();
     delete printer;
@@ -1798,3 +1826,7 @@ void MainWindow::on_actionAll_Data_for_current_CPAP_machine_triggered()
     }
 }
 
+void MainWindow::keyPressEvent(QKeyEvent * event)
+{
+    qDebug() << "Keypress:" << event->key();
+}
diff --git a/mainwindow.h b/mainwindow.h
index fb9d4f00..e900884f 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -125,6 +125,8 @@ public:
         \param QDate date
         */
     void PrintReport(gGraphView *gv,QString name, QDate date=QDate::currentDate());
+protected:
+    virtual void keyPressEvent(QKeyEvent * event);
 
 private slots:
     /*! \fn void on_action_Import_Data_triggered();
@@ -240,6 +242,8 @@ private slots:
 
     void on_summaryButton_clicked();
 
+
+
 private:
 
     Ui::MainWindow *ui;
diff --git a/overview.cpp b/overview.cpp
index b6752baa..778e3f1b 100644
--- a/overview.cpp
+++ b/overview.cpp
@@ -109,7 +109,7 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
     PTB=createGraph(tr("Pat. Trig. Br."),tr("Patient\nTriggered\nBreaths\n(%)"));
     SES=createGraph(tr("Sessions"),tr("Sessions\n(count)"));
     PULSE=createGraph(tr("Pulse Rate"),tr("Pulse Rate\n(bpm)"));
-    SPO2=createGraph(tr("SpO2"),tr("Oxygen Saturation\n(%)"));
+    SPO2=createGraph(STR_TR_SpO2,tr("Oxygen Saturation\n(%)"));
 
     WEIGHT=createGraph(STR_TR_Weight,STR_TR_Weight,YT_Weight);
     BMI=createGraph(STR_TR_BMI,tr("Body\nMass\nIndex"));
@@ -142,7 +142,7 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
     pulse->addSlice(OXI_Pulse,QColor("orange"),ST_MAX,true);
     PULSE->AddLayer(pulse);
 
-    spo2=new SummaryChart(tr("SpO2"),GT_LINE);
+    spo2=new SummaryChart(STR_TR_SpO2,GT_LINE);
     spo2->setMachineType(MT_OXIMETER);
     spo2->addSlice(OXI_SPO2,QColor("cyan"),ST_WAVG,true);
     spo2->addSlice(OXI_SPO2,QColor("light blue"),ST_90P,true);
@@ -213,16 +213,24 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
     pr=new SummaryChart(STR_UNIT_CMH2O,GT_LINE);
     //PR->setRecMinY(4.0);
     //PR->setRecMaxY(12.0);
-    pr->addSlice(CPAP_Pressure,QColor("dark green"),ST_WAVG,true);
-    pr->addSlice(CPAP_Pressure,QColor("orange"),ST_MIN,true);
-    pr->addSlice(CPAP_Pressure,QColor("red"),ST_MAX,true);
-    //pr->addSlice(CPAP_Pressure,QColor("grey"),ST_90P,true);
-    pr->addSlice(CPAP_Pressure,QColor("grey"),ST_PERC,true,0.95);
-    pr->addSlice(CPAP_EPAP,QColor("green"),ST_MIN,true);
-    pr->addSlice(CPAP_EPAP,QColor("light green"),ST_90P,true);
 
-    pr->addSlice(CPAP_IPAP,QColor("blue"),ST_MAX,true);
-    pr->addSlice(CPAP_IPAP,QColor("light blue"),ST_90P,true);
+    CPAPMode mode=(CPAPMode)(int)PROFILE.calcSettingsMax(CPAP_Mode,MT_CPAP,PROFILE.FirstDay(MT_CPAP),PROFILE.LastDay(MT_CPAP));
+
+    if (mode>=MODE_BIPAP) {
+        pr->addSlice(CPAP_EPAP,QColor("green"),ST_MIN,true);
+        pr->addSlice(CPAP_EPAP,QColor("light green"),ST_90P,true);
+
+        pr->addSlice(CPAP_IPAP,QColor("blue"),ST_MAX,true);
+        pr->addSlice(CPAP_IPAP,QColor("light blue"),ST_90P,true);
+    } else if (mode>MODE_CPAP) {
+        pr->addSlice(CPAP_Pressure,QColor("dark green"),ST_WAVG,true);
+        pr->addSlice(CPAP_Pressure,QColor("orange"),ST_MIN,true);
+        pr->addSlice(CPAP_Pressure,QColor("red"),ST_MAX,true);
+    //pr->addSlice(CPAP_Pressure,QColor("grey"),ST_90P,true);
+        pr->addSlice(CPAP_Pressure,QColor("grey"),ST_PERC,true,0.95);
+    } else {
+        pr->addSlice(CPAP_PressureMin,QColor("grey"),ST_SETWAVG,true);
+    }
     PR->AddLayer(pr);
 
     lk=new SummaryChart(tr("Avg Leak"),GT_LINE);
diff --git a/oximetry.cpp b/oximetry.cpp
index efc9ccea..b6e01d05 100644
--- a/oximetry.cpp
+++ b/oximetry.cpp
@@ -247,6 +247,12 @@ void SerialOximeter::addSpO2(qint64 time, EventDataType o2)
 
 void SerialOximeter::addPlethy(qint64 time, EventDataType pleth)
 {
+    if (!plethy) {
+        plethy=new EventList(EVL_Event);
+        session->eventlist[OXI_Plethy].push_back(plethy);
+        session->setFirst(OXI_Plethy,lasttime);
+        plethy->setFirst(lasttime);
+    }
     plethy->AddEvent(time,pleth);
     session->setCount(OXI_Plethy,plethy->count()); // update the cache
     session->setMin(OXI_Plethy,plethy->Min());
@@ -375,18 +381,15 @@ Session *SerialOximeter::createSession(QDateTime date)
     session->set_first(lasttime);
     pulse=new EventList(EVL_Event);
     spo2=new EventList(EVL_Event);
-    plethy=new EventList(EVL_Event);
+    plethy=NULL;
     session->eventlist[OXI_Pulse].push_back(pulse);
     session->eventlist[OXI_SPO2].push_back(spo2);
-    session->eventlist[OXI_Plethy].push_back(plethy);
 
     session->setFirst(OXI_Pulse,lasttime);
     session->setFirst(OXI_SPO2,lasttime);
-    session->setFirst(OXI_Plethy,lasttime);
 
     pulse->setFirst(lasttime);
     spo2->setFirst(lasttime);
-    plethy->setFirst(lasttime);
 
     m_callbacks=0;
 
diff --git a/preferencesdialog.cpp b/preferencesdialog.cpp
index f3372791..31753461 100644
--- a/preferencesdialog.cpp
+++ b/preferencesdialog.cpp
@@ -318,15 +318,15 @@ void PreferencesDialog::Save()
     profile->oxi->setSyncOximetry(ui->oximetrySync->isChecked());
     int oxigrp=ui->oximetrySync->isChecked() ? 0 : 1;
     gGraphView *gv=mainwin->getDaily()->graphView();
-    gGraph *g=gv->findGraph(tr("Pulse"));
+    gGraph *g=gv->findGraph(STR_TR_PulseRate);
     if (g) {
         g->setGroup(oxigrp);
     }
-    g=gv->findGraph(tr("SpO2"));
+    g=gv->findGraph(STR_TR_SpO2);
     if (g) {
         g->setGroup(oxigrp);
     }
-    g=gv->findGraph(tr("Plethy"));
+    g=gv->findGraph(STR_TR_Plethy);
     if (g) {
         g->setGroup(oxigrp);
     }