mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 18:50:44 +00:00
The daily screen displays day and time of the graph cursor as the mouse moves around the graphs. Since this time is displayed to the user, it should appear in the local time zone.
2572 lines
91 KiB
C++
2572 lines
91 KiB
C++
/* Daily Panel
|
|
*
|
|
* Copyright (c) 2011-2014 Mark Watkins <jedimark@users.sourceforge.net>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file COPYING in the main directory of the Linux
|
|
* distribution for more details. */
|
|
|
|
#include <QTextCharFormat>
|
|
#include <QPalette>
|
|
#include <QTextBlock>
|
|
#include <QColorDialog>
|
|
#include <QSpacerItem>
|
|
#include <QBuffer>
|
|
#include <QPixmap>
|
|
#include <QMessageBox>
|
|
#include <QResizeEvent>
|
|
#include <QScrollBar>
|
|
#include <QSpacerItem>
|
|
#include <QWebFrame>
|
|
#include <QFontMetrics>
|
|
#include <QLabel>
|
|
|
|
#include <cmath>
|
|
//#include <QPrinter>
|
|
//#include <QProgressBar>
|
|
|
|
#include "daily.h"
|
|
#include "ui_daily.h"
|
|
|
|
#include "common_gui.h"
|
|
#include "SleepLib/profiles.h"
|
|
#include "SleepLib/session.h"
|
|
#include "Graphs/graphdata_custom.h"
|
|
#include "Graphs/gLineOverlay.h"
|
|
#include "Graphs/gFlagsLine.h"
|
|
#include "Graphs/gFooBar.h"
|
|
#include "Graphs/gXAxis.h"
|
|
#include "Graphs/gYAxis.h"
|
|
#include "Graphs/gSegmentChart.h"
|
|
#include "Graphs/gStatsLine.h"
|
|
#include "Graphs/gdailysummary.h"
|
|
#include "Graphs/MinutesAtPressure.h"
|
|
|
|
//extern QProgressBar *qprogress;
|
|
extern MainWindow * mainwin;
|
|
|
|
// This was Sean Stangl's idea.. but I couldn't apply that patch.
|
|
inline QString channelInfo(ChannelID code) {
|
|
return schema::channel[code].fullname()+"\n"+schema::channel[code].description()+"\n("+schema::channel[code].units()+")";
|
|
}
|
|
|
|
void Daily::setCalendarVisible(bool visible)
|
|
{
|
|
on_calButton_toggled(visible);
|
|
}
|
|
|
|
void Daily::setSidebarVisible(bool visible)
|
|
{
|
|
QList<int> a;
|
|
|
|
int panel_width = visible ? p_profile->appearance->dailyPanelWidth() : 0;
|
|
a.push_back(panel_width);
|
|
a.push_back(this->width() - panel_width);
|
|
ui->splitter_2->setStretchFactor(1,1);
|
|
ui->splitter_2->setSizes(a);
|
|
ui->splitter_2->setStretchFactor(1,1);
|
|
}
|
|
|
|
Daily::Daily(QWidget *parent,gGraphView * shared)
|
|
:QWidget(parent), ui(new Ui::Daily)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
// Remove Incomplete Extras Tab
|
|
//ui->tabWidget->removeTab(3);
|
|
|
|
ZombieMeterMoved=false;
|
|
BookmarksChanged=false;
|
|
|
|
lastcpapday=nullptr;
|
|
|
|
setSidebarVisible(true);
|
|
|
|
layout=new QHBoxLayout();
|
|
layout->setSpacing(0);
|
|
layout->setMargin(0);
|
|
layout->setContentsMargins(0,0,0,0);
|
|
|
|
dateDisplay=new MyLabel(this);
|
|
dateDisplay->setAlignment(Qt::AlignCenter);
|
|
QFont font = dateDisplay->font();
|
|
font.setPointSizeF(font.pointSizeF()*1.3F);
|
|
dateDisplay->setFont(font);
|
|
QPalette palette = dateDisplay->palette();
|
|
palette.setColor(QPalette::Base, Qt::blue);
|
|
dateDisplay->setPalette(palette);
|
|
//dateDisplay->setTextFormat(Qt::RichText);
|
|
ui->sessionBarLayout->addWidget(dateDisplay,1);
|
|
|
|
// const bool sessbar_under_graphs=false;
|
|
// if (sessbar_under_graphs) {
|
|
// ui->sessionBarLayout->addWidget(sessbar,1);
|
|
// } else {
|
|
// ui->splitter->insertWidget(2,sessbar);
|
|
// sessbar->setMaximumHeight(sessbar->height());
|
|
// sessbar->setMinimumHeight(sessbar->height());
|
|
// }
|
|
|
|
|
|
ui->calNavWidget->setMaximumHeight(ui->calNavWidget->height());
|
|
ui->calNavWidget->setMinimumHeight(ui->calNavWidget->height());
|
|
sessbar=nullptr;
|
|
|
|
webView=new MyWebView(this);
|
|
|
|
|
|
|
|
QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
|
|
|
|
ui->tabWidget->insertTab(0,webView,QIcon(),"Details");
|
|
|
|
ui->graphFrame->setLayout(layout);
|
|
//ui->graphMainArea->setLayout(layout);
|
|
|
|
ui->graphMainArea->setAutoFillBackground(false);
|
|
|
|
GraphView=new gGraphView(ui->graphFrame,shared);
|
|
GraphView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
|
|
|
snapGV=new gGraphView(GraphView);
|
|
snapGV->setMinimumSize(172,172);
|
|
snapGV->hideSplitter();
|
|
snapGV->hide();
|
|
|
|
scrollbar=new MyScrollBar(ui->graphFrame);
|
|
scrollbar->setOrientation(Qt::Vertical);
|
|
scrollbar->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Expanding);
|
|
scrollbar->setMaximumWidth(20);
|
|
|
|
ui->bookmarkTable->setColumnCount(2);
|
|
ui->bookmarkTable->setColumnWidth(0,70);
|
|
//ui->bookmarkTable->setEditTriggers(QAbstractItemView::SelectedClicked);
|
|
//ui->bookmarkTable->setColumnHidden(2,true);
|
|
//ui->bookmarkTable->setColumnHidden(3,true);
|
|
GraphView->setScrollBar(scrollbar);
|
|
layout->addWidget(GraphView,1);
|
|
layout->addWidget(scrollbar,0);
|
|
|
|
int default_height = p_profile->appearance->graphHeight();
|
|
|
|
gGraph *GAHI = nullptr,
|
|
// *TAP = nullptr,
|
|
*SF = nullptr,
|
|
*AHI = nullptr;
|
|
|
|
const QString STR_GRAPH_DailySummary = "DailySummary";
|
|
const QString STR_GRAPH_TAP = "TimeAtPressure";
|
|
|
|
// gGraph * SG;
|
|
// graphlist[STR_GRAPH_DailySummary] = SG = new gGraph(STR_GRAPH_DailySummary, GraphView, QObject::tr("Summary"), QObject::tr("Summary of this daily information"), default_height);
|
|
// SG->AddLayer(new gLabelArea(nullptr),LayerLeft,gYAxis::Margin);
|
|
// SG->AddLayer(new gDailySummary());
|
|
|
|
graphlist[STR_GRAPH_SleepFlags] = SF = new gGraph(STR_GRAPH_SleepFlags, GraphView, STR_TR_EventFlags, STR_TR_EventFlags, default_height);
|
|
SF->setPinned(true);
|
|
|
|
ChannelID cpapcodes[] = {
|
|
CPAP_FlowRate, CPAP_MaskPressure, CPAP_Pressure, CPAP_Leak, CPAP_Snore, CPAP_FLG, CPAP_RespRate,
|
|
CPAP_TidalVolume, CPAP_MinuteVent,CPAP_PTB, CPAP_RespEvent, CPAP_Ti, CPAP_Te,
|
|
CPAP_IE, ZEO_SleepStage, POS_Inclination, POS_Orientation, CPAP_Test1
|
|
};
|
|
|
|
int cpapsize = sizeof(cpapcodes) / sizeof(ChannelID);
|
|
|
|
ChannelID oxicodes[] = {
|
|
OXI_Pulse, OXI_SPO2, OXI_Perf, OXI_Plethy
|
|
};
|
|
int oxisize = sizeof(oxicodes) / sizeof(ChannelID);
|
|
|
|
|
|
for (int i=0; i < cpapsize; ++i) {
|
|
ChannelID code = cpapcodes[i];
|
|
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
|
|
}
|
|
|
|
//int oxigrp=p_profile->ExistsAndTrue("SyncOximetry") ? 0 : 1; // Contemplating killing this setting...
|
|
for (int i=0; i < oxisize; ++i) {
|
|
ChannelID code = oxicodes[i];
|
|
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
|
|
}
|
|
|
|
if (p_profile->general->calculateRDI()) {
|
|
AHI=new gGraph("AHI", GraphView,STR_TR_RDI, channelInfo(CPAP_RDI), default_height);
|
|
} else {
|
|
AHI=new gGraph("AHI", GraphView,STR_TR_AHI, channelInfo(CPAP_AHI), default_height);
|
|
}
|
|
|
|
graphlist["AHI"] = AHI;
|
|
|
|
graphlist[STR_GRAPH_EventBreakdown] = GAHI = new gGraph(STR_GRAPH_EventBreakdown, snapGV,tr("Breakdown"),tr("events"),172);
|
|
gSegmentChart * evseg=new gSegmentChart(GST_Pie);
|
|
evseg->AddSlice(CPAP_Hypopnea,QColor(0x40,0x40,0xff,0xff),STR_TR_H);
|
|
evseg->AddSlice(CPAP_Apnea,QColor(0x20,0x80,0x20,0xff),STR_TR_UA);
|
|
evseg->AddSlice(CPAP_Obstructive,QColor(0x40,0xaf,0xbf,0xff),STR_TR_OA);
|
|
evseg->AddSlice(CPAP_ClearAirway,QColor(0xb2,0x54,0xcd,0xff),STR_TR_CA);
|
|
evseg->AddSlice(CPAP_RERA,QColor(0xff,0xff,0x80,0xff),STR_TR_RE);
|
|
evseg->AddSlice(CPAP_NRI,QColor(0x00,0x80,0x40,0xff),STR_TR_NR);
|
|
evseg->AddSlice(CPAP_FlowLimit,QColor(0x40,0x40,0x40,0xff),STR_TR_FL);
|
|
evseg->AddSlice(CPAP_SensAwake,QColor(0x40,0xC0,0x40,0xff),STR_TR_SA);
|
|
if (p_profile->cpap->userEventPieChart()) {
|
|
evseg->AddSlice(CPAP_UserFlag1,QColor(0xe0,0xe0,0xe0,0xff),tr("UF1"));
|
|
evseg->AddSlice(CPAP_UserFlag2,QColor(0xc0,0xc0,0xe0,0xff),tr("UF2"));
|
|
}
|
|
|
|
|
|
|
|
GAHI->AddLayer(evseg);
|
|
GAHI->setMargins(0,0,0,0);
|
|
|
|
gFlagsGroup *fg=new gFlagsGroup();
|
|
SF->AddLayer(fg);
|
|
|
|
|
|
SF->setBlockZoom(true);
|
|
SF->AddLayer(new gShadowArea());
|
|
|
|
SF->AddLayer(new gLabelArea(fg),LayerLeft,gYAxis::Margin);
|
|
|
|
//SF->AddLayer(new gFooBar(),LayerBottom,0,1);
|
|
SF->AddLayer(new gXAxis(COLOR_Text,false),LayerBottom,0,gXAxis::Margin);
|
|
|
|
|
|
// The following list contains graphs that don't have standard xgrid/yaxis labels
|
|
QStringList skipgraph;
|
|
skipgraph.push_back(STR_GRAPH_EventBreakdown);
|
|
skipgraph.push_back(STR_GRAPH_SleepFlags);
|
|
skipgraph.push_back(STR_GRAPH_DailySummary);
|
|
skipgraph.push_back(STR_GRAPH_TAP);
|
|
|
|
QHash<QString, gGraph *>::iterator it;
|
|
|
|
for (it = graphlist.begin(); it != graphlist.end(); ++it) {
|
|
if (skipgraph.contains(it.key())) continue;
|
|
it.value()->AddLayer(new gXGrid());
|
|
}
|
|
|
|
|
|
gLineChart *l;
|
|
l=new gLineChart(CPAP_FlowRate,false,false);
|
|
|
|
gGraph *FRW = graphlist[schema::channel[CPAP_FlowRate].code()];
|
|
|
|
// Then the graph itself
|
|
FRW->AddLayer(l);
|
|
|
|
|
|
// FRW->AddLayer(AddOXI(new gLineOverlayBar(OXI_SPO2Drop, COLOR_SPO2Drop, STR_TR_O2)));
|
|
|
|
bool square=p_profile->appearance->squareWavePlots();
|
|
gLineChart *pc=new gLineChart(CPAP_Pressure, square);
|
|
graphlist[schema::channel[CPAP_Pressure].code()]->AddLayer(pc);
|
|
|
|
// graphlist[schema::channel[CPAP_Pressure].code()]->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Ramp, COLOR_Ramp, schema::channel[CPAP_Ramp].label(), FT_Span)));
|
|
|
|
pc->addPlot(CPAP_EPAP, square);
|
|
pc->addPlot(CPAP_IPAPLo, square);
|
|
pc->addPlot(CPAP_IPAP, square);
|
|
pc->addPlot(CPAP_IPAPHi, square);
|
|
|
|
gGraph * TAP2;
|
|
graphlist[STR_GRAPH_TAP] = TAP2 = new gGraph(STR_GRAPH_TAP, GraphView, QObject::tr("By Pressure"), QObject::tr("Statistics at Pressure"), default_height);
|
|
MinutesAtPressure * map;
|
|
TAP2->AddLayer(map = new MinutesAtPressure());
|
|
TAP2->AddLayer(new gLabelArea(map),LayerLeft,gYAxis::Margin);
|
|
TAP2->setBlockSelect(true);
|
|
|
|
if (p_profile->general->calculateRDI()) {
|
|
AHI->AddLayer(new gLineChart(CPAP_RDI, square));
|
|
// AHI->AddLayer(AddCPAP(new AHIChart(QColor("#37a24b"))));
|
|
} else {
|
|
AHI->AddLayer(new gLineChart(CPAP_AHI, square));
|
|
}
|
|
|
|
// this is class wide because the leak redline can be reset in preferences..
|
|
// Better way would be having a search for linechart layers in graphlist[...]
|
|
gLineChart *leakchart=new gLineChart(CPAP_Leak, square);
|
|
// graphlist[schema::channel[CPAP_Leak].code()]->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_LargeLeak, COLOR_LargeLeak, STR_TR_LL, FT_Span)));
|
|
|
|
leakchart->addPlot(CPAP_LeakTotal, square);
|
|
leakchart->addPlot(CPAP_MaxLeak, square);
|
|
// schema::channel[CPAP_Leak].setUpperThresholdColor(Qt::red);
|
|
// schema::channel[CPAP_Leak].setLowerThresholdColor(Qt::green);
|
|
|
|
graphlist[schema::channel[CPAP_Leak].code()]->AddLayer(leakchart);
|
|
//LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_Leak, COLOR_Leak,square)));
|
|
//LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_MaxLeak, COLOR_MaxLeak,square)));
|
|
graphlist[schema::channel[CPAP_Snore].code()]->AddLayer(new gLineChart(CPAP_Snore, true));
|
|
|
|
graphlist[schema::channel[CPAP_PTB].code()]->AddLayer(new gLineChart(CPAP_PTB, square));
|
|
graphlist[schema::channel[CPAP_Test1].code()]->AddLayer(new gLineChart(CPAP_Test1, false));
|
|
|
|
|
|
gLineChart *lc = nullptr;
|
|
graphlist[schema::channel[CPAP_MaskPressure].code()]->AddLayer(new gLineChart(CPAP_MaskPressure, false));
|
|
graphlist[schema::channel[CPAP_RespRate].code()]->AddLayer(lc=new gLineChart(CPAP_RespRate, false));
|
|
|
|
graphlist[schema::channel[POS_Inclination].code()]->AddLayer(new gLineChart(POS_Inclination));
|
|
graphlist[schema::channel[POS_Orientation].code()]->AddLayer(new gLineChart(POS_Orientation));
|
|
|
|
graphlist[schema::channel[CPAP_MinuteVent].code()]->AddLayer(lc=new gLineChart(CPAP_MinuteVent, false));
|
|
lc->addPlot(CPAP_TgMV, square);
|
|
|
|
graphlist[schema::channel[CPAP_TidalVolume].code()]->AddLayer(lc=new gLineChart(CPAP_TidalVolume, false));
|
|
//lc->addPlot(CPAP_Test2,COLOR_DarkYellow,square);
|
|
|
|
//graphlist[schema::channel[CPAP_TidalVolume].code()]->AddLayer(AddCPAP(new gLineChart("TidalVolume2", square)));
|
|
graphlist[schema::channel[CPAP_FLG].code()]->AddLayer(new gLineChart(CPAP_FLG, true));
|
|
//graphlist[schema::channel[CPAP_RespiratoryEvent].code()]->AddLayer(AddCPAP(new gLineChart(CPAP_RespiratoryEvent, true)));
|
|
graphlist[schema::channel[CPAP_IE].code()]->AddLayer(lc=new gLineChart(CPAP_IE, false));
|
|
graphlist[schema::channel[CPAP_Te].code()]->AddLayer(lc=new gLineChart(CPAP_Te, false));
|
|
graphlist[schema::channel[CPAP_Ti].code()]->AddLayer(lc=new gLineChart(CPAP_Ti, false));
|
|
//lc->addPlot(CPAP_Test2,COLOR:DarkYellow,square);
|
|
|
|
graphlist[schema::channel[ZEO_SleepStage].code()]->AddLayer(new gLineChart(ZEO_SleepStage, true));
|
|
|
|
// gLineOverlaySummary *los1=new gLineOverlaySummary(STR_UNIT_EventsPerHour,5,-4);
|
|
// gLineOverlaySummary *los2=new gLineOverlaySummary(STR_UNIT_EventsPerHour,5,-4);
|
|
// graphlist[schema::channel[OXI_Pulse].code()]->AddLayer(AddOXI(los1->add(new gLineOverlayBar(OXI_PulseChange, COLOR_PulseChange, STR_TR_PC,FT_Span))));
|
|
// graphlist[schema::channel[OXI_Pulse].code()]->AddLayer(AddOXI(los1));
|
|
// graphlist[schema::channel[OXI_SPO2].code()]->AddLayer(AddOXI(los2->add(new gLineOverlayBar(OXI_SPO2Drop, COLOR_SPO2Drop, STR_TR_O2,FT_Span))));
|
|
// graphlist[schema::channel[OXI_SPO2].code()]->AddLayer(AddOXI(los2));
|
|
|
|
graphlist[schema::channel[OXI_Pulse].code()]->AddLayer(new gLineChart(OXI_Pulse, square));
|
|
graphlist[schema::channel[OXI_SPO2].code()]->AddLayer(new gLineChart(OXI_SPO2, true));
|
|
graphlist[schema::channel[OXI_Perf].code()]->AddLayer(new gLineChart(OXI_Perf, false));
|
|
graphlist[schema::channel[OXI_Plethy].code()]->AddLayer(new gLineChart(OXI_Plethy, false));
|
|
|
|
|
|
// Fix me
|
|
// gLineOverlaySummary *los3=new gLineOverlaySummary(STR_UNIT_EventsPerHour,5,-4);
|
|
// graphlist["INTPULSE"]->AddLayer(AddCPAP(los3->add(new gLineOverlayBar(OXI_PulseChange, COLOR_PulseChange, STR_TR_PC,FT_Span))));
|
|
// graphlist["INTPULSE"]->AddLayer(AddCPAP(los3));
|
|
// graphlist["INTPULSE"]->AddLayer(AddCPAP(new gLineChart(OXI_Pulse, square)));
|
|
// gLineOverlaySummary *los4=new gLineOverlaySummary(STR_UNIT_EventsPerHour,5,-4);
|
|
// graphlist["INTSPO2"]->AddLayer(AddCPAP(los4->add(new gLineOverlayBar(OXI_SPO2Drop, COLOR_SPO2Drop, STR_TR_O2,FT_Span))));
|
|
// graphlist["INTSPO2"]->AddLayer(AddCPAP(los4));
|
|
// graphlist["INTSPO2"]->AddLayer(AddCPAP(new gLineChart(OXI_SPO2, true)));
|
|
|
|
graphlist[schema::channel[CPAP_PTB].code()]->setForceMaxY(100);
|
|
graphlist[schema::channel[OXI_SPO2].code()]->setForceMaxY(100);
|
|
|
|
for (it = graphlist.begin(); it != graphlist.end(); ++it) {
|
|
if (skipgraph.contains(it.key())) continue;
|
|
|
|
it.value()->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin);
|
|
it.value()->AddLayer(new gXAxis(),LayerBottom,0,gXAxis::Margin);
|
|
}
|
|
|
|
if (p_profile->cpap->showLeakRedline()) {
|
|
schema::channel[CPAP_Leak].setUpperThreshold(p_profile->cpap->leakRedline());
|
|
} else {
|
|
schema::channel[CPAP_Leak].setUpperThreshold(0); // switch it off
|
|
}
|
|
|
|
layout->layout();
|
|
|
|
QTextCharFormat format = ui->calendar->weekdayTextFormat(Qt::Saturday);
|
|
format.setForeground(QBrush(COLOR_Black, Qt::SolidPattern));
|
|
ui->calendar->setWeekdayTextFormat(Qt::Saturday, format);
|
|
ui->calendar->setWeekdayTextFormat(Qt::Sunday, format);
|
|
|
|
Qt::DayOfWeek dow=firstDayOfWeekFromLocale();
|
|
|
|
ui->calendar->setFirstDayOfWeek(dow);
|
|
|
|
ui->tabWidget->setCurrentWidget(webView);
|
|
|
|
webView->settings()->setFontSize(QWebSettings::DefaultFontSize,QApplication::font().pointSize());
|
|
webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
|
|
connect(webView,SIGNAL(linkClicked(QUrl)),this,SLOT(Link_clicked(QUrl)));
|
|
|
|
int ews=p_profile->general->eventWindowSize();
|
|
ui->evViewSlider->setValue(ews);
|
|
ui->evViewLCD->display(ews);
|
|
|
|
|
|
icon_on=new QIcon(":/icons/session-on.png");
|
|
icon_off=new QIcon(":/icons/session-off.png");
|
|
|
|
ui->splitter->setVisible(false);
|
|
|
|
if (p_profile->general->unitSystem()==US_Archiac) {
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_POUND);
|
|
ui->weightSpinBox->setDecimals(0);
|
|
ui->ouncesSpinBox->setVisible(true);
|
|
ui->ouncesSpinBox->setSuffix(STR_UNIT_OUNCE);
|
|
} else {
|
|
ui->ouncesSpinBox->setVisible(false);
|
|
ui->weightSpinBox->setDecimals(3);
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_KG);
|
|
}
|
|
GraphView->setEmptyText(STR_Empty_NoData);
|
|
previous_date=QDate();
|
|
|
|
ui->calButton->setChecked(p_profile->appearance->calendarVisible() ? Qt::Checked : Qt::Unchecked);
|
|
on_calButton_toggled(p_profile->appearance->calendarVisible());
|
|
|
|
GraphView->resetLayout();
|
|
GraphView->LoadSettings("Daily");
|
|
|
|
connect(GraphView, SIGNAL(updateCurrentTime(double)), this, SLOT(on_LineCursorUpdate(double)));
|
|
connect(GraphView, SIGNAL(updateRange(double,double)), this, SLOT(on_RangeUpdate(double,double)));
|
|
connect(GraphView, SIGNAL(GraphsChanged()), this, SLOT(updateGraphCombo()));
|
|
|
|
GraphView->setEmptyImage(QPixmap(":/docs/sheep.png"));
|
|
}
|
|
|
|
|
|
//void Daily::populateSessionWidget()
|
|
//{
|
|
|
|
// ui->sessionWidget->clearContents();
|
|
// ui->sessionWidget->setColumnCount(2);
|
|
|
|
// QMap<QDate, Day *>::iterator it;
|
|
// QMap<QDate, Day *>::iterator it_end = p_profile->daylist.end();
|
|
|
|
// int row = 0;
|
|
// for (it = p_profile->daylist.begin(); it != it_end; ++it) {
|
|
// const QDate & date = it.key();
|
|
// Day * day = it.value();
|
|
// QList<Session *> sessions = day->getSessions(MT_CPAP);
|
|
// int size = sessions.size();
|
|
// if (size > 0) {
|
|
// QTableWidgetItem * item = new QTableWidgetItem(date.toString(Qt::SystemLocaleShortDate));
|
|
// item->setData(Qt::UserRole, date);
|
|
// ui->sessionWidget->setItem(row, 0, item);
|
|
// SessionBar * sb = new SessionBar();
|
|
|
|
// for (int i=0; i < size; i++) {
|
|
// Session * sess = sessions[i];
|
|
// QColor col = Qt::blue;
|
|
// sb->add(sess, col);
|
|
// }
|
|
// ui->sessionWidget->setCellWidget(row, 1, sb);
|
|
// row++;
|
|
// }
|
|
// }
|
|
// ui->sessionWidget->setRowCount(row-1);
|
|
// ui->sessionWidget->setCurrentCell(row-1, 0);
|
|
// ui->sessionWidget->scrollToBottom();
|
|
//}
|
|
Daily::~Daily()
|
|
{
|
|
// disconnect(sessbar, SIGNAL(toggledSession(Session*)), this, SLOT(doToggleSession(Session*)));
|
|
|
|
// Save any last minute changes..
|
|
|
|
delete ui;
|
|
delete icon_on;
|
|
delete icon_off;
|
|
}
|
|
|
|
void Daily::showEvent(QShowEvent *)
|
|
{
|
|
RedrawGraphs();
|
|
}
|
|
|
|
void Daily::closeEvent(QCloseEvent *event)
|
|
{
|
|
|
|
disconnect(webView,SIGNAL(linkClicked(QUrl)),this,SLOT(Link_clicked(QUrl)));
|
|
|
|
if (previous_date.isValid())
|
|
Unload(previous_date);
|
|
|
|
GraphView->SaveSettings("Daily");
|
|
QWidget::closeEvent(event);
|
|
event->accept();
|
|
}
|
|
|
|
|
|
void Daily::doToggleSession(Session * sess)
|
|
{
|
|
sess->setEnabled(!sess->enabled());
|
|
|
|
LoadDate(previous_date);
|
|
mainwin->getOverview()->graphView()->dataChanged();
|
|
}
|
|
|
|
void Daily::Link_clicked(const QUrl &url)
|
|
{
|
|
QString code=url.toString().section("=",0,0).toLower();
|
|
QString data=url.toString().section("=",1);
|
|
int sid=data.toInt();
|
|
Day *day=nullptr;
|
|
|
|
if (code=="togglecpapsession") { // Enable/Disable CPAP session
|
|
day=p_profile->GetDay(previous_date,MT_CPAP);
|
|
if (!day) return;
|
|
Session *sess=day->find(sid);
|
|
if (!sess)
|
|
return;
|
|
int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
|
|
sess->setEnabled(!sess->enabled());
|
|
|
|
// Reload day
|
|
LoadDate(previous_date);
|
|
webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
|
|
} else if (code=="toggleoxisession") { // Enable/Disable Oximetry session
|
|
day=p_profile->GetDay(previous_date,MT_OXIMETER);
|
|
Session *sess=day->find(sid);
|
|
if (!sess)
|
|
return;
|
|
int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
|
|
sess->setEnabled(!sess->enabled());
|
|
|
|
// Reload day
|
|
LoadDate(previous_date);
|
|
webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
|
|
} else if (code=="cpap") {
|
|
day=p_profile->GetDay(previous_date,MT_CPAP);
|
|
if (day) {
|
|
Session *sess=day->machine(MT_CPAP)->sessionlist[sid];
|
|
if (sess && sess->enabled()) {
|
|
GraphView->SetXBounds(sess->first(),sess->last());
|
|
}
|
|
}
|
|
} else if (code=="oxi") {
|
|
day=p_profile->GetDay(previous_date,MT_OXIMETER);
|
|
if (day) {
|
|
Session *sess=day->machine(MT_OXIMETER)->sessionlist[sid];
|
|
if (sess && sess->enabled()) {
|
|
GraphView->SetXBounds(sess->first(),sess->last());
|
|
}
|
|
}
|
|
|
|
} else if (code=="event") {
|
|
QList<QTreeWidgetItem *> list=ui->treeWidget->findItems(schema::channel[sid].fullname(),Qt::MatchContains);
|
|
if (list.size()>0) {
|
|
ui->treeWidget->collapseAll();
|
|
ui->treeWidget->expandItem(list.at(0));
|
|
QTreeWidgetItem *wi=list.at(0)->child(0);
|
|
ui->treeWidget->setCurrentItem(wi);
|
|
ui->tabWidget->setCurrentIndex(1);
|
|
} else {
|
|
mainwin->Notify(tr("No %1 events are recorded this day").arg(schema::channel[sid].fullname()),"",1500);
|
|
}
|
|
} else if (code=="graph") {
|
|
qDebug() << "Select graph " << data;
|
|
} else {
|
|
qDebug() << "Clicked on" << code << data;
|
|
}
|
|
}
|
|
|
|
void Daily::ReloadGraphs()
|
|
{
|
|
GraphView->setDay(nullptr);
|
|
|
|
ui->splitter->setVisible(true);
|
|
QDate d;
|
|
|
|
if (previous_date.isValid()) {
|
|
d=previous_date;
|
|
//Unload(d);
|
|
}
|
|
QDate lastcpap = p_profile->LastDay(MT_CPAP);
|
|
QDate lastoxi = p_profile->LastDay(MT_OXIMETER);
|
|
|
|
d = qMax(lastcpap, lastoxi);
|
|
|
|
if (!d.isValid()) {
|
|
d=ui->calendar->selectedDate();
|
|
}
|
|
on_calendar_currentPageChanged(d.year(),d.month());
|
|
// this fires a signal which unloads the old and loads the new
|
|
ui->calendar->blockSignals(true);
|
|
ui->calendar->setSelectedDate(d);
|
|
ui->calendar->blockSignals(false);
|
|
Load(d);
|
|
ui->calButton->setText(ui->calendar->selectedDate().toString(Qt::TextDate));
|
|
graphView()->redraw();
|
|
}
|
|
|
|
void Daily::hideSpaceHogs()
|
|
{
|
|
if (p_profile->appearance->calendarVisible()) {
|
|
ui->calendarFrame->setVisible(false);
|
|
}
|
|
}
|
|
void Daily::showSpaceHogs()
|
|
{
|
|
if (p_profile->appearance->calendarVisible()) {
|
|
ui->calendarFrame->setVisible(true);
|
|
}
|
|
}
|
|
|
|
void Daily::on_calendar_currentPageChanged(int year, int month)
|
|
{
|
|
QDate d(year,month,1);
|
|
int dom=d.daysInMonth();
|
|
|
|
for (int i=1;i<=dom;i++) {
|
|
d=QDate(year,month,i);
|
|
this->UpdateCalendarDay(d);
|
|
}
|
|
}
|
|
|
|
void Daily::UpdateEventsTree(QTreeWidget *tree,Day *day)
|
|
{
|
|
tree->clear();
|
|
if (!day) return;
|
|
|
|
tree->setColumnCount(1); // 1 visible common.. (1 hidden)
|
|
|
|
QTreeWidgetItem *root=nullptr;
|
|
QHash<ChannelID,QTreeWidgetItem *> mcroot;
|
|
QHash<ChannelID,int> mccnt;
|
|
int total_events=0;
|
|
|
|
qint64 drift=0, clockdrift=p_profile->cpap->clockDrift()*1000L;
|
|
|
|
quint32 chantype = schema::FLAG | schema::SPAN | schema::MINOR_FLAG;
|
|
if (p_profile->general->showUnknownFlags()) chantype |= schema::UNKNOWN;
|
|
QList<ChannelID> chans = day->getSortedMachineChannels(chantype);
|
|
|
|
for (QList<Session *>::iterator s=day->begin();s!=day->end();++s) {
|
|
Session * sess = *s;
|
|
if (!sess->enabled()) continue;
|
|
|
|
QHash<ChannelID,QVector<EventList *> >::iterator m;
|
|
for (int c=0; c < chans.size(); ++c) {
|
|
ChannelID code = chans.at(c);
|
|
m = sess->eventlist.find(code);
|
|
if (m == sess->eventlist.end()) continue;
|
|
|
|
drift=(sess->type() == MT_CPAP) ? clockdrift : 0;
|
|
|
|
QTreeWidgetItem *mcr;
|
|
if (mcroot.find(code)==mcroot.end()) {
|
|
int cnt=day->count(code);
|
|
if (!cnt) continue; // If no events than don't bother showing..
|
|
total_events+=cnt;
|
|
QString st=schema::channel[code].fullname();
|
|
if (st.isEmpty()) {
|
|
st=QString("Fixme %1").arg(code);
|
|
}
|
|
st+=" ";
|
|
if (cnt==1) st+=tr("%1 event").arg(cnt);
|
|
else st+=tr("%1 events").arg(cnt);
|
|
|
|
QStringList l(st);
|
|
l.append("");
|
|
mcroot[code]=mcr=new QTreeWidgetItem(root,l);
|
|
mccnt[code]=0;
|
|
} else {
|
|
mcr=mcroot[code];
|
|
}
|
|
|
|
for (int z=0;z<m.value().size();z++) {
|
|
EventList & ev=*(m.value()[z]);
|
|
|
|
for (quint32 o=0;o<ev.count();o++) {
|
|
qint64 t=ev.time(o)+drift;
|
|
|
|
if (code==CPAP_CSR) { // center it in the middle of span
|
|
t-=float(ev.raw(o)/2.0)*1000.0;
|
|
}
|
|
QStringList a;
|
|
QDateTime d=QDateTime::fromMSecsSinceEpoch(t, Qt::UTC);
|
|
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);
|
|
QTreeWidgetItem *item=new QTreeWidgetItem(a);
|
|
item->setData(0,Qt::UserRole,t);
|
|
//a.append(d.toString("yyyy-MM-dd HH:mm:ss"));
|
|
mcr->addChild(item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int cnt=0;
|
|
for (QHash<ChannelID,QTreeWidgetItem *>::iterator m=mcroot.begin();m!=mcroot.end();m++) {
|
|
tree->insertTopLevelItem(cnt++,m.value());
|
|
}
|
|
|
|
if (day->hasMachine(MT_CPAP) || day->hasMachine(MT_OXIMETER) || day->hasMachine(MT_POSITION)) {
|
|
QTreeWidgetItem * start = new QTreeWidgetItem(QStringList(tr("Session Start Times")));
|
|
QTreeWidgetItem * end = new QTreeWidgetItem(QStringList(tr("Session End Times")));
|
|
tree->insertTopLevelItem(cnt++ , start);
|
|
tree->insertTopLevelItem(cnt++ , end);
|
|
for (QList<Session *>::iterator s=day->begin(); s!=day->end(); ++s) {
|
|
QDateTime st = QDateTime::fromMSecsSinceEpoch((*s)->first(), Qt::UTC);
|
|
QDateTime et = QDateTime::fromMSecsSinceEpoch((*s)->last(), Qt::UTC);
|
|
|
|
QTreeWidgetItem * item = new QTreeWidgetItem(QStringList(st.toString("HH:mm:ss")));
|
|
item->setData(0,Qt::UserRole, (*s)->first());
|
|
start->addChild(item);
|
|
|
|
|
|
item = new QTreeWidgetItem(QStringList(et.toString("HH:mm:ss")));
|
|
item->setData(0,Qt::UserRole, (*s)->last());
|
|
end->addChild(item);
|
|
}
|
|
}
|
|
//tree->insertTopLevelItem(cnt++,new QTreeWidgetItem(QStringList("[Total Events ("+QString::number(total_events)+")]")));
|
|
tree->sortByColumn(0,Qt::AscendingOrder);
|
|
//tree->expandAll();
|
|
}
|
|
|
|
void Daily::UpdateCalendarDay(QDate date)
|
|
{
|
|
QTextCharFormat nodata;
|
|
QTextCharFormat cpaponly;
|
|
QTextCharFormat cpapjour;
|
|
QTextCharFormat oxiday;
|
|
QTextCharFormat oxicpap;
|
|
QTextCharFormat jourday;
|
|
QTextCharFormat stageday;
|
|
|
|
cpaponly.setForeground(QBrush(COLOR_Blue, Qt::SolidPattern));
|
|
cpaponly.setFontWeight(QFont::Normal);
|
|
cpapjour.setForeground(QBrush(COLOR_Blue, Qt::SolidPattern));
|
|
cpapjour.setFontWeight(QFont::Bold);
|
|
oxiday.setForeground(QBrush(COLOR_Red, Qt::SolidPattern));
|
|
oxiday.setFontWeight(QFont::Normal);
|
|
oxicpap.setForeground(QBrush(COLOR_Red, Qt::SolidPattern));
|
|
oxicpap.setFontWeight(QFont::Bold);
|
|
stageday.setForeground(QBrush(COLOR_Magenta, Qt::SolidPattern));
|
|
stageday.setFontWeight(QFont::Bold);
|
|
jourday.setForeground(QBrush(COLOR_DarkYellow, Qt::SolidPattern));
|
|
jourday.setFontWeight(QFont::Bold);
|
|
nodata.setForeground(QBrush(COLOR_Black, Qt::SolidPattern));
|
|
nodata.setFontWeight(QFont::Normal);
|
|
|
|
bool hascpap = p_profile->FindDay(date, MT_CPAP)!=nullptr;
|
|
bool hasoxi = p_profile->FindDay(date, MT_OXIMETER)!=nullptr;
|
|
bool hasjournal = p_profile->FindDay(date, MT_JOURNAL)!=nullptr;
|
|
bool hasstage = p_profile->FindDay(date, MT_SLEEPSTAGE)!=nullptr;
|
|
bool haspos = p_profile->FindDay(date, MT_POSITION)!=nullptr;
|
|
if (hascpap) {
|
|
if (hasoxi) {
|
|
ui->calendar->setDateTextFormat(date, oxicpap);
|
|
} else if (hasjournal) {
|
|
ui->calendar->setDateTextFormat(date, cpapjour);
|
|
} else if (hasstage || haspos) {
|
|
ui->calendar->setDateTextFormat(date, stageday);
|
|
} else {
|
|
ui->calendar->setDateTextFormat(date, cpaponly);
|
|
}
|
|
} else if (hasoxi) {
|
|
ui->calendar->setDateTextFormat(date, oxiday);
|
|
} else if (hasjournal) {
|
|
ui->calendar->setDateTextFormat(date, jourday);
|
|
} else if (hasstage) {
|
|
ui->calendar->setDateTextFormat(date, oxiday);
|
|
} else if (haspos) {
|
|
ui->calendar->setDateTextFormat(date, oxiday);
|
|
} else {
|
|
ui->calendar->setDateTextFormat(date, nodata);
|
|
}
|
|
ui->calendar->setHorizontalHeaderFormat(QCalendarWidget::ShortDayNames);
|
|
}
|
|
void Daily::LoadDate(QDate date)
|
|
{
|
|
if (!date.isValid()) {
|
|
qDebug() << "LoadDate called with invalid date";
|
|
return;
|
|
}
|
|
ui->calendar->blockSignals(true);
|
|
if (date.month()!=previous_date.month()) {
|
|
on_calendar_currentPageChanged(date.year(),date.month());
|
|
}
|
|
ui->calendar->setSelectedDate(date);
|
|
ui->calendar->blockSignals(false);
|
|
on_calendar_selectionChanged();
|
|
}
|
|
void Daily::on_calendar_selectionChanged()
|
|
{
|
|
QTimer::singleShot(0, this, SLOT(on_ReloadDay()));
|
|
}
|
|
|
|
void Daily::on_ReloadDay()
|
|
{
|
|
graphView()->releaseKeyboard();
|
|
QTime time;
|
|
time_t unload_time, load_time, other_time;
|
|
time.start();
|
|
|
|
this->setCursor(Qt::BusyCursor);
|
|
if (previous_date.isValid()) {
|
|
// GraphView->fadeOut();
|
|
Unload(previous_date);
|
|
}
|
|
unload_time=time.restart();
|
|
//bool fadedir=previous_date < ui->calendar->selectedDate();
|
|
ZombieMeterMoved=false;
|
|
Load(ui->calendar->selectedDate());
|
|
load_time=time.restart();
|
|
|
|
//GraphView->fadeIn(fadedir);
|
|
GraphView->redraw();
|
|
ui->calButton->setText(ui->calendar->selectedDate().toString(Qt::TextDate));
|
|
ui->calendar->setFocus(Qt::ActiveWindowFocusReason);
|
|
|
|
if (p_profile->general->unitSystem()==US_Archiac) {
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_POUND);
|
|
ui->weightSpinBox->setDecimals(0);
|
|
ui->ouncesSpinBox->setVisible(true);
|
|
ui->ouncesSpinBox->setSuffix(STR_UNIT_OUNCE);
|
|
} else {
|
|
ui->ouncesSpinBox->setVisible(false);
|
|
ui->weightSpinBox->setDecimals(3);
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_KG);
|
|
}
|
|
this->setCursor(Qt::ArrowCursor);
|
|
other_time=time.restart();
|
|
|
|
qDebug() << "Page change time (in ms): Unload ="<<unload_time<<"Load =" << load_time << "Other =" << other_time;
|
|
}
|
|
void Daily::ResetGraphLayout()
|
|
{
|
|
GraphView->resetLayout();
|
|
}
|
|
void Daily::graphtogglebutton_toggled(bool b)
|
|
{
|
|
Q_UNUSED(b)
|
|
for (int i=0;i<GraphView->size();i++) {
|
|
QString title=(*GraphView)[i]->title();
|
|
(*GraphView)[i]->setVisible(GraphToggles[title]->isChecked());
|
|
}
|
|
GraphView->updateScale();
|
|
GraphView->redraw();
|
|
}
|
|
|
|
MyWebPage::MyWebPage(QObject *parent):
|
|
QWebPage(parent)
|
|
{
|
|
// Enable plugin support
|
|
settings()->setAttribute(QWebSettings::PluginsEnabled, true);
|
|
}
|
|
|
|
QObject *MyWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList & paramNames, const QStringList & paramValues)
|
|
{
|
|
Q_UNUSED(paramNames)
|
|
Q_UNUSED(paramValues)
|
|
Q_UNUSED(url)
|
|
|
|
if (classid=="SessionBar") {
|
|
return mainwin->getDaily()->sessionBar();
|
|
}
|
|
qDebug() << "Request for unknown MyWebPage plugin";
|
|
return new QWidget();
|
|
}
|
|
|
|
MyWebView::MyWebView(QWidget *parent):
|
|
QWebView(parent),
|
|
m_page(this)
|
|
{
|
|
// Set the page of our own PageView class, MyPageView,
|
|
// because only objects of this class will handle
|
|
// object-tags correctly.
|
|
setPage(&m_page);
|
|
}
|
|
|
|
|
|
QString Daily::getSessionInformation(Day * day)
|
|
{
|
|
QString html;
|
|
if (!day) return html;
|
|
|
|
html="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
|
|
html+=QString("<tr><td colspan=5 align=center><b>"+tr("Session Information")+"</b></td></tr>");
|
|
html+="<tr><td colspan=5 align=center> </td></tr>";
|
|
QFontMetrics FM(*defaultfont);
|
|
QRect r=FM.boundingRect('@');
|
|
|
|
Machine * cpap = day->machine(MT_CPAP);
|
|
|
|
if (cpap) {
|
|
html+=QString("<tr><td colspan=5 align=center>"
|
|
"<object type=\"application/x-qt-plugin\" classid=\"SessionBar\" name=\"sessbar\" height=%1 width=100%></object>"
|
|
// "<script>"
|
|
// "sessbar.show();"
|
|
// "</script>"
|
|
"</td></tr>").arg(r.height()*3,0,10);
|
|
html+="<tr><td colspan=5 align=center> </td></tr>";
|
|
}
|
|
|
|
|
|
QDateTime fd,ld;
|
|
bool corrupted_waveform=false;
|
|
QString tooltip;
|
|
|
|
QString type;
|
|
|
|
QHash<MachineType, Machine *>::iterator mach_end = day->machines.end();
|
|
QHash<MachineType, Machine *>::iterator mi;
|
|
|
|
for (mi = day->machines.begin(); mi != mach_end; ++mi) {
|
|
if (mi.key() == MT_JOURNAL) continue;
|
|
html += "<tr><td colspan=5 align=center><i>";
|
|
switch (mi.key()) {
|
|
case MT_CPAP: type="cpap";
|
|
html+=tr("CPAP Sessions");
|
|
break;
|
|
case MT_OXIMETER: type="oxi";
|
|
html+=tr("Oximetery Sessions");
|
|
break;
|
|
case MT_SLEEPSTAGE: type="stage";
|
|
html+=tr("Sleep Stage Sessions");
|
|
break;
|
|
case MT_POSITION: type="stage";
|
|
html+=tr("Position Sensor Sessions");
|
|
break;
|
|
|
|
default:
|
|
type="unknown";
|
|
html+=tr("Unknown Session");
|
|
break;
|
|
}
|
|
html+="</i></td></tr>\n";
|
|
html+=QString("<tr>"
|
|
"<td>"+STR_TR_On+"</td>"
|
|
"<td>"+STR_TR_Date+"</td>"
|
|
"<td>"+STR_TR_Start+"</td>"
|
|
"<td>"+STR_TR_End+"</td>"
|
|
"<td>"+tr("Duration")+"</td></tr>");
|
|
|
|
QList<Session *> sesslist = day->getSessions(mi.key(), true);
|
|
|
|
for (QList<Session *>::iterator s=sesslist.begin(); s != sesslist.end(); ++s) {
|
|
if (((*s)->type() == MT_CPAP) &&
|
|
((*s)->settings.find(CPAP_BrokenWaveform) != (*s)->settings.end()))
|
|
corrupted_waveform=true;
|
|
|
|
fd=QDateTime::fromTime_t((*s)->first()/1000L);
|
|
ld=QDateTime::fromTime_t((*s)->last()/1000L);
|
|
int len=(*s)->length()/1000L;
|
|
int h=len/3600;
|
|
int m=(len/60) % 60;
|
|
int s1=len % 60;
|
|
|
|
Session *sess=*s;
|
|
|
|
QString tooltip = QObject::tr("Click to %1 this session.").arg(sess->enabled() ? QObject::tr("disable") : QObject::tr("enable"));
|
|
html+=QString("<tr class='datarow2'><td colspan=5 align=center>%2</td></tr>"
|
|
"<tr class='datarow2'>"
|
|
"<td width=26><a href='toggle"+type+"session=%1'>"
|
|
"<img src='qrc:/icons/session-%4.png' width=24px title=\""+tooltip+"\"></a></td>"
|
|
"<td align=left>%5</td>"
|
|
"<td align=left>%6</td>"
|
|
"<td align=left>%7</td>"
|
|
"<td align=left>%3</td></tr>"
|
|
)
|
|
.arg((*s)->session())
|
|
.arg(QObject::tr("%1 Session #%2").arg((*s)->machine()->loaderName()).arg((*s)->session(),8,10,QChar('0')))
|
|
.arg(QString("%1h %2m %3s").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')).arg(s1,2,10,QChar('0')))
|
|
.arg((sess->enabled() ? "on" : "off"))
|
|
.arg(fd.date().toString(Qt::SystemLocaleShortDate))
|
|
.arg(fd.toString("HH:mm:ss"))
|
|
.arg(ld.toString("HH:mm:ss"));
|
|
#ifdef SESSION_DEBUG
|
|
for (int i=0; i< sess->session_files.size(); ++i) {
|
|
html+=QString("<tr><td colspan=5 align=center>%1</td></tr>").arg(sess->session_files[i].section("/",-1));
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (corrupted_waveform) {
|
|
html+=QString("<tr><td colspan=5 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>";
|
|
return html;
|
|
}
|
|
|
|
QString Daily::getMachineSettings(Day * day) {
|
|
QString html;
|
|
|
|
Machine * cpap = day->machine(MT_CPAP);
|
|
if (cpap && day->hasEnabledSessions(MT_CPAP)) {
|
|
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> </td></tr>";
|
|
|
|
if ((day->settingExists(CPAP_BrokenSummary))) {
|
|
html+="<tr><td colspan=5 align=center><i>"+tr("Machine Settings Unavailable")+"</i></td></tr></table><hr/>\n";
|
|
return html;
|
|
}
|
|
|
|
QMap<QString, QString> other;
|
|
Session * sess = day->firstSession(MT_CPAP);
|
|
|
|
QHash<ChannelID, QVariant>::iterator it;
|
|
QHash<ChannelID, QVariant>::iterator it_end;
|
|
if (sess) {
|
|
it_end = sess->settings.end();
|
|
it = sess->settings.begin();
|
|
}
|
|
QMap<int, QString> first;
|
|
|
|
CPAPLoader * loader = qobject_cast<CPAPLoader *>(cpap->loader());
|
|
|
|
ChannelID cpapmode = loader->CPAPModeChannel();
|
|
schema::Channel & chan = schema::channel[cpapmode];
|
|
first[cpapmode] = QString("<tr class='datarow'><td><a class='info' href='#'>%1<span>%2</span></a></td><td colspan=4>%3</td></tr>")
|
|
.arg(chan.label())
|
|
.arg(chan.description())
|
|
.arg(day->getCPAPMode());
|
|
|
|
|
|
if (sess) for (; it != it_end; ++it) {
|
|
ChannelID code = it.key();
|
|
|
|
if ((code <= 1) || (code == RMS9_MaskOnTime) || (code == CPAP_Mode) || (code == cpapmode) || (code == CPAP_SummaryOnly)) continue;
|
|
|
|
schema::Channel & chan = schema::channel[code];
|
|
|
|
QString data;
|
|
|
|
if (chan.datatype() == schema::LOOKUP) {
|
|
data = chan.option(it.value().toInt());
|
|
} else if (chan.datatype() == schema::BOOL) {
|
|
data = (it.value().toBool() ? STR_TR_Yes : STR_TR_No);
|
|
} else if (chan.datatype() == schema::DOUBLE) {
|
|
data = QString().number(it.value().toDouble(),'f',1) + " "+chan.units();
|
|
} else {
|
|
data = it.value().toString() + " "+ chan.units();
|
|
}
|
|
QString tmp = QString("<tr class='datarow'><td><a class='info' href='#'>%1<span>%2</span></a></td><td colspan=4>%3</td></tr>")
|
|
.arg(schema::channel[code].label())
|
|
.arg(schema::channel[code].description())
|
|
.arg(data);
|
|
|
|
|
|
if ((code == CPAP_IPAP)
|
|
|| (code == CPAP_EPAP)
|
|
|| (code == CPAP_IPAPHi)
|
|
|| (code == CPAP_EPAPHi)
|
|
|| (code == CPAP_IPAPLo)
|
|
|| (code == CPAP_EPAPLo)
|
|
|| (code == CPAP_PressureMin)
|
|
|| (code == CPAP_PressureMax)
|
|
|| (code == CPAP_Pressure)
|
|
|| (code == CPAP_PSMin)
|
|
|| (code == CPAP_PSMax)
|
|
|| (code == CPAP_PS)) {
|
|
first[code] = tmp;
|
|
} else {
|
|
other[schema::channel[code].label()] = tmp;
|
|
}
|
|
}
|
|
|
|
ChannelID order[] = { cpapmode, CPAP_Pressure, CPAP_PressureMin, CPAP_PressureMax, CPAP_EPAP, CPAP_EPAPLo, CPAP_EPAPHi, CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_PS, CPAP_PSMin, CPAP_PSMax };
|
|
int os = sizeof(order) / sizeof(ChannelID);
|
|
for (int i=0 ;i < os; ++i) {
|
|
if (first.contains(order[i])) html += first[order[i]];
|
|
}
|
|
|
|
for (QMap<QString,QString>::iterator it = other.begin(); it != other.end(); ++it) {
|
|
html += it.value();
|
|
}
|
|
|
|
/* ChannelID pr_level_chan = NoChannel;
|
|
ChannelID pr_mode_chan = NoChannel;
|
|
ChannelID hum_stat_chan = NoChannel;
|
|
ChannelID hum_level_chan = NoChannel;
|
|
CPAPLoader * loader = dynamic_cast<CPAPLoader *>(cpap->machine->loader());
|
|
if (loader) {
|
|
pr_level_chan = loader->PresReliefLevel();
|
|
pr_mode_chan = loader->PresReliefMode();
|
|
hum_stat_chan = loader->HumidifierConnected();
|
|
hum_level_chan = loader->HumidifierLevel();
|
|
}
|
|
|
|
if ((pr_level_chan != NoChannel) && (cpap->settingExists(pr_level_chan))) {
|
|
QString flexstr = cpap->getPressureRelief();
|
|
|
|
html+=QString("<tr><td><a class='info' href='#'>%1<span>%2</span></a></td><td colspan=4>%3</td></tr>")
|
|
.arg(schema::channel[pr_mode_chan].label())
|
|
.arg(schema::channel[pr_mode_chan].description())
|
|
.arg(flexstr);
|
|
}
|
|
|
|
|
|
if (cpap->settingExists(hum_level_chan)) {
|
|
int humid=round(cpap->settings_wavg(hum_level_chan));
|
|
html+=QString("<tr><td><a class='info' href='#'>"+schema::channel[hum_level_chan].label()+"<span>%1</span></a></td><td colspan=4>%2</td></tr>")
|
|
.arg(schema::channel[hum_level_chan].description())
|
|
.arg(humid == 0 ? STR_GEN_Off : "x"+QString::number(humid));
|
|
} */
|
|
html+="</table>";
|
|
html+="<hr/>\n";
|
|
}
|
|
return html;
|
|
}
|
|
|
|
QString Daily::getOximeterInformation(Day * day)
|
|
{
|
|
QString html;
|
|
Machine * oxi = day->machine(MT_OXIMETER);
|
|
if (oxi && day->hasEnabledSessions(MT_OXIMETER)) {
|
|
html="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
|
|
html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Oximeter Information"));
|
|
html+="<tr><td colspan=5 align=center> </td></tr>";
|
|
html+="<tr><td colspan=5 align=center>"+oxi->brand()+" "+oxi->model()+"</td></tr>\n";
|
|
html+="<tr><td colspan=5 align=center> </td></tr>";
|
|
html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3%)</td></tr>").arg(tr("SpO2 Desaturations")).arg(day->count(OXI_SPO2Drop)).arg((100.0/day->hours(MT_OXIMETER)) * (day->sum(OXI_SPO2Drop)/3600.0),0,'f',2);
|
|
html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3%)</td></tr>").arg(tr("Pulse Change events")).arg(day->count(OXI_PulseChange)).arg((100.0/day->hours(MT_OXIMETER)) * (day->sum(OXI_PulseChange)/3600.0),0,'f',2);
|
|
html+=QString("<tr><td colspan=5 align=center>%1: %2%</td></tr>").arg(tr("SpO2 Baseline Used")).arg(day->settings_wavg(OXI_SPO2Drop),0,'f',2); // CHECKME: Should this value be wavg OXI_SPO2 isntead?
|
|
html+="</table>\n";
|
|
html+="<hr/>\n";
|
|
}
|
|
return html;
|
|
}
|
|
|
|
QString Daily::getCPAPInformation(Day * day)
|
|
{
|
|
QString html;
|
|
if (!day)
|
|
return html;
|
|
|
|
Machine * cpap = day->machine(MT_CPAP);
|
|
if (!cpap) return html;
|
|
|
|
|
|
MachineInfo info = cpap->getInfo();
|
|
|
|
html="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
|
|
html+="<tr><td align=center><a class=info2 href='#'>"+info.brand + " "+ info.series+"<br/> "+info.model+"<span>";
|
|
QString tooltip=("Model "+info.modelnumber+" - "+info.serial);
|
|
tooltip=tooltip.replace(" "," ");
|
|
|
|
html+=tooltip;
|
|
html+="</span></td></tr>\n";
|
|
//CPAPMode mode=(CPAPMode)(int)cpap->settings_max(CPAP_Mode);
|
|
html+="<tr><td align=center>";
|
|
|
|
html+=tr("PAP Mode: %1<br/>").arg(day->getCPAPMode());
|
|
html+= day->getPressureSettings();
|
|
html+="</td></tr>\n";
|
|
if ((day->settingExists(CPAP_BrokenSummary))) {
|
|
html+="<tr><td> </td></tr>\n";
|
|
html+=QString("<tr><td colspan=2><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+":</b> "+ tr("This day has missing pressure, mode and settings data."));
|
|
}
|
|
|
|
html+="</table>\n";
|
|
html+="<hr/>\n";
|
|
return html;
|
|
}
|
|
|
|
|
|
QString Daily::getStatisticsInfo(Day * day)
|
|
{
|
|
if (!day) return QString();
|
|
|
|
Machine *cpap = day->machine(MT_CPAP);
|
|
// *oxi = day->machine(MT_OXIMETER),
|
|
// *pos = day->machine(MT_POSITION);
|
|
|
|
|
|
int mididx=p_profile->general->prefCalcMiddle();
|
|
SummaryType ST_mid;
|
|
if (mididx==0) ST_mid=ST_PERC;
|
|
if (mididx==1) ST_mid=ST_WAVG;
|
|
if (mididx==2) ST_mid=ST_AVG;
|
|
|
|
float percentile=p_profile->general->prefCalcPercentile()/100.0;
|
|
|
|
SummaryType ST_max=p_profile->general->prefCalcMax() ? ST_PERC : ST_MAX;
|
|
const EventDataType maxperc=0.995F;
|
|
|
|
QString midname;
|
|
if (ST_mid==ST_WAVG) midname=STR_TR_WAvg;
|
|
else if (ST_mid==ST_AVG) midname=STR_TR_Avg;
|
|
else if (ST_mid==ST_PERC) midname=STR_TR_Med;
|
|
|
|
QString html;
|
|
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Statistics"));
|
|
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(STR_TR_Channel)
|
|
.arg(STR_TR_Min)
|
|
.arg(midname)
|
|
.arg(tr("%1%2").arg(percentile*100,0,'f',0).arg(STR_UNIT_Percentage))
|
|
.arg(STR_TR_Max);
|
|
|
|
ChannelID chans[]={
|
|
CPAP_Pressure,CPAP_EPAP,CPAP_IPAP,CPAP_PS,CPAP_PTB,
|
|
CPAP_MinuteVent, 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, POS_Inclination, POS_Orientation
|
|
};
|
|
int numchans=sizeof(chans)/sizeof(ChannelID);
|
|
int ccnt=0;
|
|
EventDataType tmp,med,perc,mx,mn;
|
|
|
|
for (int i=0;i<numchans;i++) {
|
|
|
|
ChannelID code=chans[i];
|
|
|
|
if (!day->channelHasData(code))
|
|
continue;
|
|
|
|
QString tooltip=schema::channel[code].description();
|
|
|
|
if (!schema::channel[code].units().isEmpty()) tooltip+=" ("+schema::channel[code].units()+")";
|
|
|
|
if (ST_max == ST_MAX) {
|
|
mx=day->Max(code);
|
|
} else {
|
|
mx=day->percentile(code,maxperc);
|
|
}
|
|
|
|
mn=day->Min(code);
|
|
perc=day->percentile(code,percentile);
|
|
|
|
if (ST_mid == ST_PERC) {
|
|
med=day->percentile(code,0.5);
|
|
tmp=day->wavg(code);
|
|
if (tmp>0 || mx==0) {
|
|
tooltip+=QString("<br/>"+STR_TR_WAvg+": %1").arg(tmp,0,'f',2);
|
|
}
|
|
} else if (ST_mid == ST_WAVG) {
|
|
med=day->wavg(code);
|
|
tmp=day->percentile(code,0.5);
|
|
if (tmp>0 || mx==0) {
|
|
tooltip+=QString("<br/>"+STR_TR_Median+": %1").arg(tmp,0,'f',2);
|
|
}
|
|
} else if (ST_mid == ST_AVG) {
|
|
med=day->avg(code);
|
|
tmp=day->percentile(code,0.5);
|
|
if (tmp>0 || mx==0) {
|
|
tooltip+=QString("<br/>"+STR_TR_Median+": %1").arg(tmp,0,'f',2);
|
|
}
|
|
}
|
|
|
|
html+=QString("<tr class='datarow'><td align=left class='info' onmouseover=\"style.color='blue';\" onmouseout=\"style.color='"+COLOR_Text.name()+"';\">%1<span>%6</span></td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>")
|
|
.arg(schema::channel[code].label())
|
|
.arg(mn,0,'f',2)
|
|
.arg(med,0,'f',2)
|
|
.arg(perc,0,'f',2)
|
|
.arg(mx,0,'f',2)
|
|
.arg(tooltip);
|
|
ccnt++;
|
|
|
|
}
|
|
|
|
if (GraphView->isEmpty() && ((ccnt>0) || (cpap && day->summaryOnly()))) {
|
|
html+="<tr><td colspan=5> </td></tr>\n";
|
|
html+=QString("<tr><td colspan=5 align=center><i>%1</i></td></tr>").arg("<b>"+STR_MessageBox_PleaseNote+"</b> "+ tr("This day just contains summary data, only limited information is available ."));
|
|
} else if (cpap) {
|
|
html+="<tr><td colspan=5> </td></tr>";
|
|
|
|
if ((cpap->loaderName() == STR_MACH_ResMed) || ((cpap->loaderName() == STR_MACH_PRS1) && (p_profile->cpap->resyncFromUserFlagging()))) {
|
|
int ttia = day->sum(CPAP_Obstructive) + day->sum(CPAP_ClearAirway) + day->sum(CPAP_Apnea) + day->sum(CPAP_Hypopnea);
|
|
int h = ttia / 3600;
|
|
int m = ttia / 60 % 60;
|
|
int s = ttia % 60;
|
|
if (ttia > 0) {
|
|
html+="<tr><td colspan=3 align='left' bgcolor='white'><b>"+tr("Total time in apnea")+
|
|
QString("</b></td><td colspan=2 bgcolor='white'>%1</td></tr>").arg(QString().sprintf("%02i:%02i:%02i",h,m,s));
|
|
}
|
|
|
|
}
|
|
float hours = day->hours(MT_CPAP);
|
|
|
|
if (p_profile->cpap->showLeakRedline()) {
|
|
float rlt = day->timeAboveThreshold(CPAP_Leak, p_profile->cpap->leakRedline()) / 60.0;
|
|
float pc = 100.0 / hours * rlt;
|
|
html+="<tr><td colspan=3 align='left' bgcolor='white'><b>"+tr("Time over leak redline")+
|
|
QString("</b></td><td colspan=2 bgcolor='white'>%1%</td></tr>").arg(pc, 0, 'f', 3);
|
|
}
|
|
int l = day->sum(CPAP_Ramp);
|
|
|
|
if (l > 0) {
|
|
html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("Total ramp time")+
|
|
QString("</td><td colspan=2 bgcolor='white'>%1:%2:%3</td></tr>").arg(l / 3600, 2, 10, QChar('0')).arg((l / 60) % 60, 2, 10, QChar('0')).arg(l % 60, 2, 10, QChar('0'));
|
|
float v = (hours - (float(l) / 3600.0));
|
|
int q = v * 3600.0;
|
|
html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("Time outside of ramp")+
|
|
QString("</td><td colspan=2 bgcolor='white'>%1:%2:%3</td></tr>").arg(q / 3600, 2, 10, QChar('0')).arg((q / 60) % 60, 2, 10, QChar('0')).arg(q % 60, 2, 10, QChar('0'));
|
|
|
|
// EventDataType hc = day->count(CPAP_Hypopnea) - day->countInsideSpan(CPAP_Ramp, CPAP_Hypopnea);
|
|
// EventDataType oc = day->count(CPAP_Obstructive) - day->countInsideSpan(CPAP_Ramp, CPAP_Obstructive);
|
|
|
|
//EventDataType tc = day->count(CPAP_Hypopnea) + day->count(CPAP_Obstructive);
|
|
// EventDataType ahi = (hc+oc) / v;
|
|
// Not sure if i was trying to be funny, and left on my replication of Devilbiss's bug here... :P
|
|
|
|
// html+="<tr><td colspan=3 align='left' bgcolor='white'>"+tr("AHI excluding ramp")+
|
|
// QString("</td><td colspan=2 bgcolor='white'>%1</td></tr>").arg(ahi, 0, 'f', 2);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
html+="</table>\n";
|
|
html+="<hr/>\n";
|
|
return html;
|
|
}
|
|
|
|
QString Daily::getEventBreakdown(Day * cpap)
|
|
{
|
|
Q_UNUSED(cpap)
|
|
QString html;
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
|
|
html+="</table>";
|
|
return html;
|
|
}
|
|
|
|
QString Daily::getSleepTime(Day * day)
|
|
{
|
|
//cpap, Day * oxi
|
|
QString html;
|
|
|
|
if (!day || (day->hours() < 0.0000001))
|
|
return html;
|
|
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
html+="<tr><td align='center'><b>"+STR_TR_Date+"</b></td><td align='center'><b>"+tr("Sleep")+"</b></td><td align='center'><b>"+tr("Wake")+"</b></td><td align='center'><b>"+STR_UNIT_Hours+"</b></td></tr>";
|
|
int tt=qint64(day->total_time())/1000L;
|
|
QDateTime date=QDateTime::fromTime_t(day->first()/1000L);
|
|
QDateTime date2=QDateTime::fromTime_t(day->last()/1000L);
|
|
|
|
int h=tt/3600;
|
|
int m=(tt/60)%60;
|
|
int s=tt % 60;
|
|
html+=QString("<tr><td align='center'>%1</td><td align='center'>%2</td><td align='center'>%3</td><td align='center'>%4</td></tr>\n")
|
|
.arg(date.date().toString(Qt::SystemLocaleShortDate))
|
|
.arg(date.toString("HH:mm:ss"))
|
|
.arg(date2.toString("HH:mm:ss"))
|
|
.arg(QString().sprintf("%02i:%02i:%02i",h,m,s));
|
|
html+="</table>\n";
|
|
// html+="<hr/>";
|
|
|
|
return html;
|
|
}
|
|
|
|
|
|
|
|
void Daily::Load(QDate date)
|
|
{
|
|
dateDisplay->setText("<i>"+date.toString(Qt::SystemLocaleLongDate)+"</i>");
|
|
previous_date=date;
|
|
|
|
Day * day = p_profile->GetDay(date);
|
|
Machine *cpap = nullptr,
|
|
*oxi = nullptr,
|
|
//*stage = nullptr,
|
|
*posit = nullptr;
|
|
|
|
if (day) {
|
|
cpap = day->machine(MT_CPAP);
|
|
oxi = day->machine(MT_OXIMETER);
|
|
// stage = day->machine(MT_SLEEPSTAGE);
|
|
posit = day->machine(MT_POSITION);
|
|
}
|
|
|
|
if (!p_profile->session->cacheSessions()) {
|
|
// Getting trashed on purge last day...
|
|
|
|
// lastcpapday can get purged and be invalid
|
|
if (lastcpapday && (lastcpapday!=day)) {
|
|
for (QMap<QDate, Day *>::iterator di = p_profile->daylist.begin(); di!= p_profile->daylist.end(); ++di) {
|
|
Day * d = di.value();
|
|
if (d->eventsLoaded()) {
|
|
if (d->useCounter() == 0) {
|
|
d->CloseEvents();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Don't really see a point in unlinked oximetery sessions anymore... All I can say is BLEH...
|
|
// if ((cpap && oxi) && day->hasEnabledSessions(MT_OXIMETER)) {
|
|
// int gr;
|
|
|
|
// if (qAbs(day->first(MT_CPAP) - day->first(MT_OXIMETER)) > 30000) {
|
|
// mainwin->Notify(tr("Oximetry data exists for this day, but its timestamps are too different, so the Graphs will not be linked."),"",3000);
|
|
// gr=1;
|
|
// } else
|
|
// gr=0;
|
|
|
|
// (*GraphView)[schema::channel[OXI_Pulse].code()]->setGroup(gr);
|
|
// (*GraphView)[schema::channel[OXI_SPO2].code()]->setGroup(gr);
|
|
// (*GraphView)[schema::channel[OXI_Plethy].code()]->setGroup(gr);
|
|
// }
|
|
lastcpapday=day;
|
|
|
|
QString html="<html><head><style type='text/css'>"
|
|
"p,a,td,body { font-family: '"+QApplication::font().family()+"'; }"
|
|
"p,a,td,body { font-size: "+QString::number(QApplication::font().pointSize() + 2)+"px; }"
|
|
"tr.datarow:nth-child(even) {"
|
|
"background-color: #f8f8f8;"
|
|
"}"
|
|
"tr.datarow2:nth-child(4n-1) {"
|
|
"background-color: #f8f8f8;"
|
|
"}"
|
|
"tr.datarow2:nth-child(4n+0) {"
|
|
"background-color: #f8f8f8;"
|
|
"}"
|
|
"table.curved {"
|
|
"border: 1px solid gray;"
|
|
"border-radius:10px;"
|
|
"-moz-border-radius:10px;"
|
|
"-webkit-border-radius:10px;"
|
|
"page-break-after:auto;"
|
|
"-fs-table-paginate: paginate;"
|
|
"}"
|
|
|
|
"</style>"
|
|
"<link rel='stylesheet' type='text/css' href='qrc:/docs/tooltips.css' />"
|
|
"<script language='javascript'><!--"
|
|
"func dosession(sessid) {"
|
|
""
|
|
"}"
|
|
"--></script>"
|
|
"</head>"
|
|
"<body leftmargin=0 rightmargin=0 topmargin=0 marginwidth=0 marginheight=0>";
|
|
QString tmp;
|
|
|
|
if (day) {
|
|
day->OpenEvents();
|
|
}
|
|
GraphView->setDay(day);
|
|
|
|
|
|
// UpdateOXIGraphs(oxi);
|
|
// UpdateCPAPGraphs(cpap);
|
|
// UpdateSTAGEGraphs(stage);
|
|
// UpdatePOSGraphs(posit);
|
|
UpdateEventsTree(ui->treeWidget, day);
|
|
|
|
// FIXME:
|
|
// Generating entire statistics because bookmarks may have changed.. (This updates the side panel too)
|
|
mainwin->GenerateStatistics();
|
|
|
|
snapGV->setDay(day);
|
|
|
|
// GraphView->ResetBounds(false);
|
|
|
|
// wtf is hiding the scrollbars for???
|
|
// if (!cpap && !oxi) {
|
|
// scrollbar->hide();
|
|
// } else {
|
|
// scrollbar->show();
|
|
// }
|
|
|
|
QString modestr;
|
|
CPAPMode mode=MODE_UNKNOWN;
|
|
QString a;
|
|
bool isBrick=false;
|
|
|
|
updateGraphCombo();
|
|
ui->eventsCombo->clear();
|
|
|
|
quint32 chans = schema::SPAN | schema::FLAG | schema::MINOR_FLAG;
|
|
if (p_profile->general->showUnknownFlags()) chans |= schema::UNKNOWN;
|
|
|
|
QList<ChannelID> available;
|
|
if (day) available.append(day->getSortedMachineChannels(chans));
|
|
|
|
for (int i=0; i < available.size(); ++i) {
|
|
ChannelID code = available.at(i);
|
|
schema::Channel & chan = schema::channel[code];
|
|
ui->eventsCombo->addItem(chan.enabled() ? *icon_on : * icon_off, chan.label(), code);
|
|
ui->eventsCombo->setItemData(i, chan.fullname(), Qt::ToolTipRole);
|
|
|
|
}
|
|
|
|
if (!cpap) {
|
|
GraphView->setEmptyImage(QPixmap(":/docs/sheep.png"));
|
|
}
|
|
if (cpap) {
|
|
//QHash<schema::ChanType, QList<schema::Channel *> > list;
|
|
|
|
|
|
float hours=day->hours(MT_CPAP);
|
|
if (GraphView->isEmpty() && (hours>0)) {
|
|
if (!p_profile->hasChannel(CPAP_Obstructive) && !p_profile->hasChannel(CPAP_Hypopnea)) {
|
|
GraphView->setEmptyText(STR_Empty_Brick);
|
|
|
|
GraphView->setEmptyImage(QPixmap(":/icons/sadface.png"));
|
|
isBrick=true;
|
|
} else {
|
|
GraphView->setEmptyImage(QPixmap(":/docs/sheep.png"));
|
|
}
|
|
}
|
|
|
|
mode=(CPAPMode)(int)day->settings_max(CPAP_Mode);
|
|
|
|
modestr=schema::channel[CPAP_Mode].m_options[mode];
|
|
|
|
EventDataType ahi=(day->count(CPAP_Obstructive)+day->count(CPAP_Hypopnea)+day->count(CPAP_ClearAirway)+day->count(CPAP_Apnea));
|
|
if (p_profile->general->calculateRDI()) ahi+=day->count(CPAP_RERA);
|
|
ahi/=hours;
|
|
|
|
if (hours>0) {
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
html+="<tr>";
|
|
if (!isBrick) {
|
|
ChannelID ahichan=CPAP_AHI;
|
|
QString ahiname=STR_TR_AHI;
|
|
if (p_profile->general->calculateRDI()) {
|
|
ahichan=CPAP_RDI;
|
|
ahiname=STR_TR_RDI;
|
|
}
|
|
html+=QString("<td colspan=4 bgcolor='%1' align=center><a class=info2 href='#'><font size=+4 color='%2'><b>%3</b></font><span>%4</span></a> <font size=+4 color='%2'><b>%5</b></font></td>\n")
|
|
.arg("#F88017").arg(COLOR_Text.name()).arg(ahiname).arg(schema::channel[ahichan].fullname()).arg(ahi,0,'f',2);
|
|
} else {
|
|
html+=QString("<td colspan=5 bgcolor='%1' align=center><font size=+4 color='yellow'>%2</font></td>\n")
|
|
.arg("#F88017").arg(tr("BRICK! :("));
|
|
}
|
|
html+="</tr>\n";
|
|
html+="</table>\n";
|
|
html+=getCPAPInformation(day);
|
|
html+=getSleepTime(day);
|
|
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
|
|
|
|
quint32 zchans = schema::SPAN | schema::FLAG;
|
|
bool show_minors = true;
|
|
if (p_profile->general->showUnknownFlags()) zchans |= schema::UNKNOWN;
|
|
|
|
if (show_minors) zchans |= schema::MINOR_FLAG;
|
|
QList<ChannelID> available = day->getSortedMachineChannels(zchans);
|
|
|
|
EventDataType val;
|
|
QHash<ChannelID, EventDataType> values;
|
|
for (int i=0; i < available.size(); ++i) {
|
|
ChannelID code = available.at(i);
|
|
schema::Channel & chan = schema::channel[code];
|
|
if (!chan.enabled()) continue;
|
|
QString data;
|
|
if (chan.type() == schema::SPAN) {
|
|
val = (100.0 / hours)*(day->sum(code)/3600.0);
|
|
data = QString("%1%").arg(val,0,'f',2);
|
|
} else {
|
|
val = day->count(code) / hours;
|
|
data = QString("%1").arg(val,0,'f',2);
|
|
}
|
|
values[code] = val;
|
|
QColor altcolor = (brightness(chan.defaultColor()) < 0.3) ? Qt::white : Qt::black; // pick a contrasting color
|
|
html+=QString("<tr><td align='left' bgcolor='%1'><b><font color='%2'><a href='event=%5'>%3</a></font></b></td><td width=20% bgcolor='%1'><b><font color='%2'>%4</font></b></td></tr>\n")
|
|
.arg(chan.defaultColor().name()).arg(altcolor.name()).arg(chan.fullname()).arg(data).arg(code);
|
|
}
|
|
|
|
|
|
// for (int i=0;i<numchans;i++) {
|
|
// if (!cpap->channelHasData(chans[i].id))
|
|
// continue;
|
|
// if ((cpap->machine->loaderName() == STR_MACH_PRS1) && (chans[i].id == CPAP_VSnore))
|
|
// continue;
|
|
// html+=QString("<tr><td align='left' bgcolor='%1'><b><font color='%2'><a href='event=%5'>%3</a></font></b></td><td width=20% bgcolor='%1'><b><font color='%2'>%4</font></b></td></tr>\n")
|
|
// .arg(schema::channel[chans[i].id].defaultColor().name()).arg(chans[i].color2.name()).arg(schema::channel[chans[i].id].fullname()).arg(chans[i].value,0,'f',2).arg(chans[i].id);
|
|
|
|
// // keep in case tooltips are needed
|
|
// //html+=QString("<tr><td align='left' bgcolor='%1'><b><font color='%2'><a class=info href='event=%6'>%3<span>%4</span></a></font></b></td><td width=20% bgcolor='%1'><b><font color='%2'>%5</font></b></td></tr>\n")
|
|
// // .arg(chans[i].color.name()).arg(chans[i].color2.name()).arg(chans[i].name).arg(schema::channel[chans[i].id].description()).arg(chans[i].value,0,'f',2).arg(chans[i].id);
|
|
// }
|
|
html+="</table>";
|
|
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
// Show Event Breakdown pie chart
|
|
if ((hours > 0) && p_profile->appearance->graphSnapshots()) { // AHI Pie Chart
|
|
if ((values[CPAP_Obstructive] + values[CPAP_Hypopnea] + values[CPAP_ClearAirway] + values[CPAP_Apnea] + values[CPAP_RERA] + values[CPAP_FlowLimit] + values[CPAP_SensAwake])>0) {
|
|
html+="<tr><td align=center> </td></tr>";
|
|
html+=QString("<tr><td align=center><b>%1</b></td></tr>").arg(tr("Event Breakdown"));
|
|
eventBreakdownPie()->setShowTitle(false);
|
|
|
|
int w=155;
|
|
int h=155;
|
|
QPixmap pixmap=eventBreakdownPie()->renderPixmap(w,h,false);
|
|
if (!pixmap.isNull()) {
|
|
QByteArray byteArray;
|
|
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
|
|
buffer.open(QIODevice::WriteOnly);
|
|
pixmap.save(&buffer, "PNG");
|
|
html += "<tr><td align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + QString("\" width='%1' height='%2px'></td></tr>\n").arg(w).arg(h);
|
|
} else {
|
|
html += "<tr><td align=center>Unable to display Pie Chart on this system</td></tr>\n";
|
|
}
|
|
} else if (day->channelHasData(CPAP_Obstructive)
|
|
|| day->channelHasData(CPAP_Hypopnea)
|
|
|| day->channelHasData(CPAP_ClearAirway)
|
|
|| day->channelHasData(CPAP_RERA)
|
|
|| day->channelHasData(CPAP_Apnea)
|
|
|| day->channelHasData(CPAP_FlowLimit)
|
|
|| day->channelHasData(CPAP_SensAwake)
|
|
) {
|
|
html += "<tr><td align=center><img src=\"qrc:/docs/0.0.gif\"></td></tr>\n";
|
|
}
|
|
}
|
|
|
|
html+="</table>\n";
|
|
html+="<hr/>\n";
|
|
|
|
} else {
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
|
if (!isBrick) {
|
|
html+="<tr><td colspan='5'> </td></tr>\n";
|
|
if (day->size()>0) {
|
|
html+="<tr><td colspan=5 align='center'><font size='+3'>"+tr("Sessions all off!")+"</font></td></tr>";
|
|
html+="<tr><td align=center><img src='qrc:/docs/sheep.png' width=120px></td></tr>";
|
|
html+="<tr bgcolor='#89abcd'><td colspan=5 align='center'><i><font color=white size=+1>"+tr("Sessions exist for this day but are switched off.")+"</font></i></td></tr>\n";
|
|
GraphView->setEmptyText(STR_Empty_NoSessions);
|
|
} else {
|
|
html+="<tr><td colspan=5 align='center'><b><h2>"+tr("Impossibly short session")+"</h2></b></td></tr>";
|
|
html+="<tr><td colspan=5 align='center'><i>"+tr("Zero hours??")+"</i></td></tr>\n";
|
|
}
|
|
} else { // machine is a brick
|
|
html+="<tr><td colspan=5 align='center'><b><h2>"+tr("BRICK :(")+"</h2></b></td></tr>";
|
|
html+="<tr><td colspan=5 align='center'><i>"+tr("Sorry, your machine only provides compliance data.")+"</i></td></tr>\n";
|
|
html+="<tr><td colspan=5 align='center'><i>"+tr("Complain to your Equipment Provider!")+"</i></td></tr>\n";
|
|
}
|
|
html+="<tr><td colspan='5'> </td></tr>\n";
|
|
html+="</table>\n";
|
|
}
|
|
|
|
} // if (!CPAP)
|
|
else html+=getSleepTime(day);
|
|
|
|
if ((cpap && !isBrick && (day->hours()>0)) || oxi || posit) {
|
|
|
|
html+=getStatisticsInfo(day);
|
|
|
|
} else {
|
|
if (cpap && day->hours(MT_CPAP)<0.0000001) {
|
|
} else if (!isBrick) {
|
|
html+="<table cellspacing=0 cellpadding=0 border=0 height=100% width=100%>";
|
|
html+="<tr height=25%><td align=center></td></tr>";
|
|
html+="<tr><td align=center><font size='+3'>"+tr("\"Nothing's here!\"")+"</font></td></tr>";
|
|
html+="<tr><td align=center><img src='qrc:/docs/sheep.png' width=120px></td></tr>";
|
|
html+="<tr height=5px><td align=center></td></tr>";
|
|
html+="<tr bgcolor='#89abcd'><td align=center><i><font size=+1 color=white>"+tr("Bob is bored with this days lack of data.")+"</font></i></td></tr>";
|
|
html+="<tr height=25%><td align=center></td></tr>";
|
|
html+="</table>\n";
|
|
}
|
|
|
|
}
|
|
if (day) {
|
|
html+=getOximeterInformation(day);
|
|
html+=getMachineSettings(day);
|
|
html+=getSessionInformation(day);
|
|
}
|
|
|
|
html+="</body></html>";
|
|
|
|
QColor cols[]={
|
|
COLOR_Gold,
|
|
QColor("light blue"),
|
|
};
|
|
const int maxcolors=sizeof(cols)/sizeof(QColor);
|
|
QList<Session *>::iterator i;
|
|
|
|
// WebView trashes it without asking.. :(
|
|
if (cpap) {
|
|
sessbar=new SessionBar(this);
|
|
sessbar->setMouseTracking(true);
|
|
connect(sessbar, SIGNAL(sessionClicked(Session*)), this, SLOT(doToggleSession(Session*)));
|
|
int c=0;
|
|
|
|
for (i=day->begin();i!=day->end();++i) {
|
|
Session * s=*i;
|
|
if ((*s).type() == MT_CPAP)
|
|
sessbar->add(s, cols[c % maxcolors]);
|
|
c++;
|
|
}
|
|
} else sessbar=nullptr;
|
|
//sessbar->update();
|
|
|
|
webView->setHtml(html);
|
|
|
|
ui->JournalNotes->clear();
|
|
|
|
ui->bookmarkTable->clearContents();
|
|
ui->bookmarkTable->setRowCount(0);
|
|
QStringList sl;
|
|
//sl.append(tr("Starts"));
|
|
//sl.append(tr("Notes"));
|
|
ui->bookmarkTable->setHorizontalHeaderLabels(sl);
|
|
ui->ZombieMeter->blockSignals(true);
|
|
ui->weightSpinBox->blockSignals(true);
|
|
ui->ouncesSpinBox->blockSignals(true);
|
|
|
|
ui->weightSpinBox->setValue(0);
|
|
ui->ouncesSpinBox->setValue(0);
|
|
ui->ZombieMeter->setValue(5);
|
|
ui->ouncesSpinBox->blockSignals(false);
|
|
ui->weightSpinBox->blockSignals(false);
|
|
ui->ZombieMeter->blockSignals(false);
|
|
ui->BMI->display(0);
|
|
ui->BMI->setVisible(false);
|
|
ui->BMIlabel->setVisible(false);
|
|
|
|
BookmarksChanged=false;
|
|
Session *journal=GetJournalSession(date);
|
|
if (journal) {
|
|
bool ok;
|
|
if (journal->settings.contains(Journal_Notes))
|
|
ui->JournalNotes->setHtml(journal->settings[Journal_Notes].toString());
|
|
|
|
if (journal->settings.contains(Journal_Weight)) {
|
|
double kg=journal->settings[Journal_Weight].toDouble(&ok);
|
|
|
|
if (p_profile->general->unitSystem()==US_Metric) {
|
|
ui->weightSpinBox->setDecimals(3);
|
|
ui->weightSpinBox->blockSignals(true);
|
|
ui->weightSpinBox->setValue(kg);
|
|
ui->weightSpinBox->blockSignals(false);
|
|
ui->ouncesSpinBox->setVisible(false);
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_KG);
|
|
} else {
|
|
float ounces=(kg*1000.0)/ounce_convert;
|
|
int pounds=ounces/16.0;
|
|
double oz;
|
|
double frac=modf(ounces,&oz);
|
|
ounces=(int(ounces) % 16)+frac;
|
|
ui->weightSpinBox->blockSignals(true);
|
|
ui->ouncesSpinBox->blockSignals(true);
|
|
ui->weightSpinBox->setValue(pounds);
|
|
ui->ouncesSpinBox->setValue(ounces);
|
|
ui->ouncesSpinBox->blockSignals(false);
|
|
ui->weightSpinBox->blockSignals(false);
|
|
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_POUND);
|
|
ui->weightSpinBox->setDecimals(0);
|
|
ui->ouncesSpinBox->setVisible(true);
|
|
ui->ouncesSpinBox->setSuffix(STR_UNIT_OUNCE);
|
|
}
|
|
double height=p_profile->user->height()/100.0;
|
|
if (height>0 && kg>0) {
|
|
double bmi=kg/(height*height);
|
|
ui->BMI->setVisible(true);
|
|
ui->BMIlabel->setVisible(true);
|
|
ui->BMI->display(bmi);
|
|
}
|
|
}
|
|
|
|
if (journal->settings.contains(Journal_ZombieMeter)) {
|
|
ui->ZombieMeter->blockSignals(true);
|
|
ui->ZombieMeter->setValue(journal->settings[Journal_ZombieMeter].toDouble(&ok));
|
|
ui->ZombieMeter->blockSignals(false);
|
|
}
|
|
|
|
if (journal->settings.contains(Bookmark_Start)) {
|
|
QVariantList start=journal->settings[Bookmark_Start].toList();
|
|
QVariantList end=journal->settings[Bookmark_End].toList();
|
|
QStringList notes=journal->settings[Bookmark_Notes].toStringList();
|
|
|
|
ui->bookmarkTable->blockSignals(true);
|
|
|
|
|
|
qint64 clockdrift=p_profile->cpap->clockDrift()*1000L,drift;
|
|
Day * dday=p_profile->GetDay(previous_date,MT_CPAP);
|
|
drift=(dday!=nullptr) ? clockdrift : 0;
|
|
|
|
bool ok;
|
|
for (int i=0;i<start.size();i++) {
|
|
qint64 st=start.at(i).toLongLong(&ok)+drift;
|
|
qint64 et=end.at(i).toLongLong(&ok)+drift;
|
|
|
|
QDateTime d=QDateTime::fromTime_t(st/1000L);
|
|
//int row=ui->bookmarkTable->rowCount();
|
|
ui->bookmarkTable->insertRow(i);
|
|
QTableWidgetItem *tw=new QTableWidgetItem(notes.at(i));
|
|
QTableWidgetItem *dw=new QTableWidgetItem(d.time().toString("HH:mm:ss"));
|
|
dw->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
|
|
ui->bookmarkTable->setItem(i,0,dw);
|
|
ui->bookmarkTable->setItem(i,1,tw);
|
|
tw->setData(Qt::UserRole,st);
|
|
tw->setData(Qt::UserRole+1,et);
|
|
} // for (int i
|
|
ui->bookmarkTable->blockSignals(false);
|
|
} // if (journal->settings.contains(Bookmark_Start))
|
|
} // if (journal)
|
|
}
|
|
|
|
void Daily::UnitsChanged()
|
|
{
|
|
double kg;
|
|
if (p_profile->general->unitSystem()==US_Archiac) {
|
|
kg=ui->weightSpinBox->value();
|
|
float ounces=(kg*1000.0)/ounce_convert;
|
|
int pounds=ounces/16;
|
|
float oz=fmodf(ounces,16);
|
|
ui->weightSpinBox->setValue(pounds);
|
|
ui->ouncesSpinBox->setValue(oz);
|
|
|
|
ui->weightSpinBox->setDecimals(0);
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_POUND);
|
|
ui->ouncesSpinBox->setVisible(true);
|
|
ui->ouncesSpinBox->setSuffix(STR_UNIT_OUNCE);
|
|
} else {
|
|
kg=(ui->weightSpinBox->value()*(ounce_convert*16.0))+(ui->ouncesSpinBox->value()*ounce_convert);
|
|
kg/=1000.0;
|
|
ui->weightSpinBox->setDecimals(3);
|
|
ui->weightSpinBox->setValue(kg);
|
|
ui->ouncesSpinBox->setVisible(false);
|
|
ui->weightSpinBox->setSuffix(STR_UNIT_KG);
|
|
}
|
|
}
|
|
|
|
void Daily::clearLastDay()
|
|
{
|
|
lastcpapday=nullptr;
|
|
}
|
|
|
|
|
|
void Daily::Unload(QDate date)
|
|
{
|
|
if (!date.isValid()) {
|
|
date = getDate();
|
|
if (!date.isValid()) {
|
|
graphView()->setDay(nullptr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
webView->setHtml("");
|
|
Session *journal=GetJournalSession(date);
|
|
|
|
bool nonotes=ui->JournalNotes->toPlainText().isEmpty();
|
|
if (journal) {
|
|
QString jhtml=ui->JournalNotes->toHtml();
|
|
if ((!journal->settings.contains(Journal_Notes) && !nonotes) || (journal->settings[Journal_Notes]!=jhtml)) {
|
|
journal->settings[Journal_Notes]=jhtml;
|
|
journal->SetChanged(true);
|
|
}
|
|
} else {
|
|
if (!nonotes) {
|
|
journal=CreateJournalSession(date);
|
|
if (!nonotes) {
|
|
journal->settings[Journal_Notes]=ui->JournalNotes->toHtml();
|
|
journal->SetChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (journal) {
|
|
if (nonotes) {
|
|
QHash<ChannelID,QVariant>::iterator it=journal->settings.find(Journal_Notes);
|
|
if (it!=journal->settings.end()) {
|
|
journal->settings.erase(it);
|
|
}
|
|
}
|
|
if (journal->IsChanged()) {
|
|
journal->settings[LastUpdated]=QDateTime::currentDateTime();
|
|
// blah.. was updating overview graphs here.. Was too slow.
|
|
}
|
|
Machine *jm=p_profile->GetMachine(MT_JOURNAL);
|
|
if (jm) jm->SaveSummary(); //(journal);
|
|
}
|
|
UpdateCalendarDay(date);
|
|
}
|
|
|
|
void Daily::on_JournalNotesItalic_clicked()
|
|
{
|
|
QTextCursor cursor = ui->JournalNotes->textCursor();
|
|
if (!cursor.hasSelection())
|
|
cursor.select(QTextCursor::WordUnderCursor);
|
|
|
|
QTextCharFormat format=cursor.charFormat();
|
|
|
|
format.setFontItalic(!format.fontItalic());
|
|
|
|
|
|
cursor.mergeCharFormat(format);
|
|
//ui->JournalNotes->mergeCurrentCharFormat(format);
|
|
|
|
}
|
|
|
|
void Daily::on_JournalNotesBold_clicked()
|
|
{
|
|
QTextCursor cursor = ui->JournalNotes->textCursor();
|
|
if (!cursor.hasSelection())
|
|
cursor.select(QTextCursor::WordUnderCursor);
|
|
|
|
QTextCharFormat format=cursor.charFormat();
|
|
|
|
int fw=format.fontWeight();
|
|
if (fw!=QFont::Bold)
|
|
format.setFontWeight(QFont::Bold);
|
|
else
|
|
format.setFontWeight(QFont::Normal);
|
|
|
|
cursor.mergeCharFormat(format);
|
|
//ui->JournalNotes->mergeCurrentCharFormat(format);
|
|
|
|
}
|
|
|
|
void Daily::on_JournalNotesFontsize_activated(int index)
|
|
{
|
|
QTextCursor cursor = ui->JournalNotes->textCursor();
|
|
if (!cursor.hasSelection())
|
|
cursor.select(QTextCursor::WordUnderCursor);
|
|
|
|
QTextCharFormat format=cursor.charFormat();
|
|
|
|
QFont font=format.font();
|
|
int fontsize=10;
|
|
|
|
if (index==1) fontsize=15;
|
|
else if (index==2) fontsize=25;
|
|
|
|
font.setPointSize(fontsize);
|
|
format.setFont(font);
|
|
|
|
cursor.mergeCharFormat(format);
|
|
}
|
|
|
|
void Daily::on_JournalNotesColour_clicked()
|
|
{
|
|
QColor col=QColorDialog::getColor(COLOR_Black,this,tr("Pick a Colour")); //,QColorDialog::NoButtons);
|
|
if (!col.isValid()) return;
|
|
|
|
QTextCursor cursor = ui->JournalNotes->textCursor();
|
|
if (!cursor.hasSelection())
|
|
cursor.select(QTextCursor::WordUnderCursor);
|
|
|
|
QBrush b(col);
|
|
QPalette newPalette = palette();
|
|
newPalette.setColor(QPalette::ButtonText, col);
|
|
ui->JournalNotesColour->setPalette(newPalette);
|
|
|
|
QTextCharFormat format=cursor.charFormat();
|
|
|
|
format.setForeground(b);
|
|
|
|
cursor.setCharFormat(format);
|
|
}
|
|
Session * Daily::CreateJournalSession(QDate date)
|
|
{
|
|
Machine *m = p_profile->GetMachine(MT_JOURNAL);
|
|
if (!m) {
|
|
m=new Machine(0);
|
|
MachineInfo info;
|
|
info.loadername = "Journal";
|
|
info.serial = m->hexid();
|
|
info.brand = "Journal";
|
|
info.type = MT_JOURNAL;
|
|
m->setInfo(info);
|
|
m->setType(MT_JOURNAL);
|
|
p_profile->AddMachine(m);
|
|
}
|
|
|
|
Session *sess=new Session(m,0);
|
|
qint64 st,et;
|
|
|
|
Day *cday=p_profile->GetDay(date);
|
|
if (cday) {
|
|
st=cday->first();
|
|
et=cday->last();
|
|
} else {
|
|
QDateTime dt(date,QTime(20,0));
|
|
st=qint64(dt.toTime_t())*1000L;
|
|
et=st+3600000L;
|
|
}
|
|
sess->SetSessionID(st / 1000L);
|
|
sess->set_first(st);
|
|
sess->set_last(et);
|
|
m->AddSession(sess);
|
|
return sess;
|
|
}
|
|
Session * Daily::GetJournalSession(QDate date) // Get the first journal session
|
|
{
|
|
Day *day=p_profile->GetDay(date, MT_JOURNAL);
|
|
if (day) {
|
|
Session * session = day->firstSession(MT_JOURNAL);
|
|
if (!session) {
|
|
session = CreateJournalSession(date);
|
|
}
|
|
return session;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
void Daily::RedrawGraphs()
|
|
{
|
|
// setting this here, because it needs to be done when preferences change
|
|
if (p_profile->cpap->showLeakRedline()) {
|
|
schema::channel[CPAP_Leak].setUpperThreshold(p_profile->cpap->leakRedline());
|
|
} else {
|
|
schema::channel[CPAP_Leak].setUpperThreshold(0); // switch it off
|
|
}
|
|
|
|
GraphView->redraw();
|
|
}
|
|
|
|
void Daily::on_LineCursorUpdate(double time)
|
|
{
|
|
if (time > 1) {
|
|
// use local time since this string is displayed to the user
|
|
QDateTime dt = QDateTime::fromMSecsSinceEpoch(time, Qt::LocalTime);
|
|
QString txt = dt.toString("MMM dd HH:mm:ss.zzz");
|
|
dateDisplay->setText(txt);
|
|
} else dateDisplay->setText(QString(GraphView->emptyText()));
|
|
}
|
|
|
|
void Daily::on_RangeUpdate(double minx, double /*maxx*/)
|
|
{
|
|
if (minx > 1) {
|
|
dateDisplay->setText(GraphView->getRangeString());
|
|
} else {
|
|
dateDisplay->setText(QString(GraphView->emptyText()));
|
|
}
|
|
|
|
/* // Delay render some stats...
|
|
Day * day = GraphView->day();
|
|
if (day) {
|
|
QTime time;
|
|
time.start();
|
|
QList<ChannelID> list = day->getSortedMachineChannels(schema::WAVEFORM);
|
|
for (int i=0; i< list.size();i++) {
|
|
schema::Channel & chan = schema::channel[list.at(i)];
|
|
ChannelID code = chan.id();
|
|
if (!day->channelExists(code)) continue;
|
|
float avg = day->rangeAvg(code, minx, maxx);
|
|
float wavg = day->rangeWavg(code, minx, maxx);
|
|
float median = day->rangePercentile(code, 0.5, minx, maxx);
|
|
float p90 = day->rangePercentile(code, 0.9, minx, maxx);
|
|
// qDebug() << chan.label()
|
|
// << "AVG=" << avg
|
|
// << "WAVG=" << wavg;
|
|
// << "MED" << median
|
|
// << "90%" << p90;
|
|
}
|
|
|
|
qDebug() << time.elapsed() << "ms";
|
|
}*/
|
|
}
|
|
|
|
|
|
void Daily::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
|
|
{
|
|
Q_UNUSED(column);
|
|
QDateTime d;
|
|
if (!item->data(0,Qt::UserRole).isNull()) {
|
|
qint64 winsize=qint64(p_profile->general->eventWindowSize())*60000L;
|
|
qint64 t=item->data(0,Qt::UserRole).toLongLong();
|
|
|
|
double st=t-(winsize/2);
|
|
double et=t+(winsize/2);
|
|
|
|
gGraph *g=GraphView->findGraph(STR_GRAPH_SleepFlags);
|
|
if (!g) return;
|
|
if (st<g->rmin_x) {
|
|
st=g->rmin_x;
|
|
et=st+winsize;
|
|
}
|
|
if (et>g->rmax_x) {
|
|
et=g->rmax_x;
|
|
st=et-winsize;
|
|
}
|
|
GraphView->SetXBounds(st,et);
|
|
}
|
|
}
|
|
|
|
void Daily::on_treeWidget_itemSelectionChanged()
|
|
{
|
|
if (ui->treeWidget->selectedItems().size()==0) return;
|
|
QTreeWidgetItem *item=ui->treeWidget->selectedItems().at(0);
|
|
if (!item) return;
|
|
on_treeWidget_itemClicked(item, 0);
|
|
}
|
|
|
|
void Daily::on_JournalNotesUnderline_clicked()
|
|
{
|
|
QTextCursor cursor = ui->JournalNotes->textCursor();
|
|
if (!cursor.hasSelection())
|
|
cursor.select(QTextCursor::WordUnderCursor);
|
|
|
|
QTextCharFormat format=cursor.charFormat();
|
|
|
|
format.setFontUnderline(!format.fontUnderline());
|
|
|
|
cursor.mergeCharFormat(format);
|
|
//ui->JournalNotes->mergeCurrentCharFormat(format);
|
|
}
|
|
|
|
void Daily::on_prevDayButton_clicked()
|
|
{
|
|
if (!p_profile->ExistsAndTrue("SkipEmptyDays")) {
|
|
LoadDate(previous_date.addDays(-1));
|
|
} else {
|
|
QDate d=previous_date;
|
|
for (int i=0;i<90;i++) {
|
|
d=d.addDays(-1);
|
|
if (p_profile->GetDay(d)) {
|
|
LoadDate(d);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Daily::on_nextDayButton_clicked()
|
|
{
|
|
if (!p_profile->ExistsAndTrue("SkipEmptyDays")) {
|
|
LoadDate(previous_date.addDays(1));
|
|
} else {
|
|
QDate d=previous_date;
|
|
for (int i=0;i<90;i++) {
|
|
d=d.addDays(1);
|
|
if (p_profile->GetDay(d)) {
|
|
LoadDate(d);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Daily::on_calButton_toggled(bool checked)
|
|
{
|
|
bool b=checked;
|
|
ui->calendarFrame->setVisible(b);
|
|
p_profile->appearance->setCalendarVisible(b);
|
|
|
|
if (!b) {
|
|
ui->calButton->setArrowType(Qt::DownArrow);
|
|
} else {
|
|
ui->calButton->setArrowType(Qt::UpArrow);
|
|
}
|
|
}
|
|
|
|
|
|
void Daily::on_todayButton_clicked()
|
|
{
|
|
// QDate d=QDate::currentDate();
|
|
// if (d > p_profile->LastDay()) {
|
|
QDate lastcpap = p_profile->LastDay(MT_CPAP);
|
|
QDate lastoxi = p_profile->LastDay(MT_OXIMETER);
|
|
|
|
QDate d = qMax(lastcpap, lastoxi);
|
|
// }
|
|
LoadDate(d);
|
|
}
|
|
|
|
void Daily::on_evViewSlider_valueChanged(int value)
|
|
{
|
|
ui->evViewLCD->display(value);
|
|
p_profile->general->setEventWindowSize(value);
|
|
|
|
int winsize=value*60;
|
|
|
|
gGraph *g=GraphView->findGraph(STR_GRAPH_SleepFlags);
|
|
if (!g) return;
|
|
qint64 st=g->min_x;
|
|
qint64 et=g->max_x;
|
|
qint64 len=et-st;
|
|
qint64 d=st+len/2.0;
|
|
|
|
st=d-(winsize/2)*1000;
|
|
et=d+(winsize/2)*1000;
|
|
if (st<g->rmin_x) {
|
|
st=g->rmin_x;
|
|
et=st+winsize*1000;
|
|
}
|
|
if (et>g->rmax_x) {
|
|
et=g->rmax_x;
|
|
st=et-winsize*1000;
|
|
}
|
|
GraphView->SetXBounds(st,et);
|
|
}
|
|
|
|
void Daily::on_bookmarkTable_itemClicked(QTableWidgetItem *item)
|
|
{
|
|
int row=item->row();
|
|
qint64 st,et;
|
|
|
|
// qint64 clockdrift=p_profile->cpap->clockDrift()*1000L,drift;
|
|
// Day * dday=p_profile->GetDay(previous_date,MT_CPAP);
|
|
// drift=(dday!=nullptr) ? clockdrift : 0;
|
|
|
|
QTableWidgetItem *it=ui->bookmarkTable->item(row,1);
|
|
bool ok;
|
|
st=it->data(Qt::UserRole).toLongLong(&ok);
|
|
et=it->data(Qt::UserRole+1).toLongLong(&ok);
|
|
qint64 st2=0,et2=0,st3,et3;
|
|
Day * day=p_profile->GetGoodDay(previous_date,MT_CPAP);
|
|
if (day) {
|
|
st2=day->first();
|
|
et2=day->last();
|
|
}
|
|
Day * oxi=p_profile->GetGoodDay(previous_date,MT_OXIMETER);
|
|
if (oxi) {
|
|
st3=oxi->first();
|
|
et3=oxi->last();
|
|
}
|
|
if (oxi && day) {
|
|
st2=qMin(st2,st3);
|
|
et2=qMax(et2,et3);
|
|
} else if (oxi) {
|
|
st2=st3;
|
|
et2=et3;
|
|
} else if (!day) return;
|
|
if ((et<st2) || (st>et2)) {
|
|
mainwin->Notify(tr("This bookmarked is in a currently disabled area.."));
|
|
return;
|
|
}
|
|
|
|
if (st<st2) st=st2;
|
|
if (et>et2) et=et2;
|
|
GraphView->SetXBounds(st,et);
|
|
GraphView->redraw();
|
|
}
|
|
|
|
void Daily::addBookmark(qint64 st, qint64 et, QString text)
|
|
{
|
|
ui->bookmarkTable->blockSignals(true);
|
|
QDateTime d=QDateTime::fromTime_t(st/1000L, Qt::UTC);
|
|
int row=ui->bookmarkTable->rowCount();
|
|
ui->bookmarkTable->insertRow(row);
|
|
QTableWidgetItem *tw=new QTableWidgetItem(text);
|
|
QTableWidgetItem *dw=new QTableWidgetItem(d.time().toString("HH:mm:ss"));
|
|
dw->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
|
|
ui->bookmarkTable->setItem(row,0,dw);
|
|
ui->bookmarkTable->setItem(row,1,tw);
|
|
qint64 clockdrift=p_profile->cpap->clockDrift()*1000L,drift;
|
|
Day * day=p_profile->GetDay(previous_date,MT_CPAP);
|
|
drift=(day!=nullptr) ? clockdrift : 0;
|
|
|
|
// Counter CPAP clock drift for storage, in case user changes it later on
|
|
// This won't fix the text string names..
|
|
|
|
tw->setData(Qt::UserRole,st-drift);
|
|
tw->setData(Qt::UserRole+1,et-drift);
|
|
|
|
ui->bookmarkTable->blockSignals(false);
|
|
update_Bookmarks();
|
|
mainwin->updateFavourites();
|
|
|
|
}
|
|
|
|
void Daily::on_addBookmarkButton_clicked()
|
|
{
|
|
qint64 st,et;
|
|
GraphView->GetXBounds(st,et);
|
|
QDateTime d=QDateTime::fromTime_t(st/1000L);
|
|
|
|
addBookmark(st,et, tr("Bookmark at %1").arg(d.time().toString("HH:mm:ss")));
|
|
}
|
|
void Daily::update_Bookmarks()
|
|
{
|
|
QVariantList start;
|
|
QVariantList end;
|
|
QStringList notes;
|
|
QTableWidgetItem *item;
|
|
for (int row=0;row<ui->bookmarkTable->rowCount();row++) {
|
|
item=ui->bookmarkTable->item(row,1);
|
|
|
|
start.push_back(item->data(Qt::UserRole));
|
|
end.push_back(item->data(Qt::UserRole+1));
|
|
notes.push_back(item->text());
|
|
}
|
|
Session *journal=GetJournalSession(previous_date);
|
|
if (!journal) {
|
|
journal=CreateJournalSession(previous_date);
|
|
}
|
|
|
|
journal->settings[Bookmark_Start]=start;
|
|
journal->settings[Bookmark_End]=end;
|
|
journal->settings[Bookmark_Notes]=notes;
|
|
journal->settings[LastUpdated]=QDateTime::currentDateTime();
|
|
journal->SetChanged(true);
|
|
BookmarksChanged=true;
|
|
mainwin->updateFavourites();
|
|
}
|
|
|
|
void Daily::on_removeBookmarkButton_clicked()
|
|
{
|
|
int row=ui->bookmarkTable->currentRow();
|
|
if (row>=0) {
|
|
ui->bookmarkTable->blockSignals(true);
|
|
ui->bookmarkTable->removeRow(row);
|
|
ui->bookmarkTable->blockSignals(false);
|
|
update_Bookmarks();
|
|
}
|
|
mainwin->updateFavourites();
|
|
}
|
|
void Daily::on_ZombieMeter_valueChanged(int action)
|
|
{
|
|
Q_UNUSED(action);
|
|
ZombieMeterMoved=true;
|
|
Session *journal=GetJournalSession(previous_date);
|
|
if (!journal) {
|
|
journal=CreateJournalSession(previous_date);
|
|
}
|
|
journal->settings[Journal_ZombieMeter]=ui->ZombieMeter->value();
|
|
journal->SetChanged(true);
|
|
|
|
// shouldn't be needed anymore with new overview model..
|
|
//if (mainwin->getOverview()) mainwin->getOverview()->ResetGraph("Zombie");
|
|
}
|
|
|
|
void Daily::on_bookmarkTable_itemChanged(QTableWidgetItem *item)
|
|
{
|
|
Q_UNUSED(item);
|
|
update_Bookmarks();
|
|
}
|
|
|
|
void Daily::on_weightSpinBox_valueChanged(double arg1)
|
|
{
|
|
// Update the BMI display
|
|
double kg;
|
|
if (p_profile->general->unitSystem()==US_Archiac) {
|
|
kg=((arg1*pound_convert) + (ui->ouncesSpinBox->value()*ounce_convert)) / 1000.0;
|
|
} else kg=arg1;
|
|
double height=p_profile->user->height()/100.0;
|
|
if ((height>0) && (kg>0)) {
|
|
double bmi=kg/(height * height);
|
|
ui->BMI->display(bmi);
|
|
ui->BMI->setVisible(true);
|
|
}
|
|
}
|
|
|
|
void Daily::on_weightSpinBox_editingFinished()
|
|
{
|
|
double arg1=ui->weightSpinBox->value();
|
|
|
|
double height=p_profile->user->height()/100.0;
|
|
Session *journal=GetJournalSession(previous_date);
|
|
if (!journal) {
|
|
journal=CreateJournalSession(previous_date);
|
|
}
|
|
|
|
double kg;
|
|
if (p_profile->general->unitSystem()==US_Archiac) {
|
|
kg=((arg1*pound_convert) + (ui->ouncesSpinBox->value()*ounce_convert)) / 1000.0;
|
|
} else {
|
|
kg=arg1;
|
|
}
|
|
journal->settings[Journal_Weight]=kg;
|
|
gGraphView *gv=mainwin->getOverview()->graphView();
|
|
gGraph *g;
|
|
if (gv) {
|
|
g=gv->findGraph(STR_GRAPH_Weight);
|
|
if (g) g->setDay(nullptr);
|
|
}
|
|
if ((height>0) && (kg>0)) {
|
|
double bmi=kg/(height * height);
|
|
ui->BMI->display(bmi);
|
|
ui->BMI->setVisible(true);
|
|
journal->settings[Journal_BMI]=bmi;
|
|
if (gv) {
|
|
g=gv->findGraph(STR_GRAPH_BMI);
|
|
if (g) g->setDay(nullptr);
|
|
}
|
|
}
|
|
journal->SetChanged(true);
|
|
}
|
|
|
|
void Daily::on_ouncesSpinBox_valueChanged(int arg1)
|
|
{
|
|
// just update for BMI display
|
|
double height=p_profile->user->height()/100.0;
|
|
double kg=((ui->weightSpinBox->value()*pound_convert) + (arg1*ounce_convert)) / 1000.0;
|
|
if ((height>0) && (kg>0)) {
|
|
double bmi=kg/(height * height);
|
|
ui->BMI->display(bmi);
|
|
ui->BMI->setVisible(true);
|
|
}
|
|
}
|
|
|
|
void Daily::on_ouncesSpinBox_editingFinished()
|
|
{
|
|
double arg1=ui->ouncesSpinBox->value();
|
|
Session *journal=GetJournalSession(previous_date);
|
|
if (!journal) {
|
|
journal=CreateJournalSession(previous_date);
|
|
}
|
|
double height=p_profile->user->height()/100.0;
|
|
double kg=((ui->weightSpinBox->value()*pound_convert) + (arg1*ounce_convert)) / 1000.0;
|
|
journal->settings[Journal_Weight]=kg;
|
|
|
|
gGraph *g;
|
|
if (mainwin->getOverview()) {
|
|
g=mainwin->getOverview()->graphView()->findGraph(STR_GRAPH_Weight);
|
|
if (g) g->setDay(nullptr);
|
|
}
|
|
|
|
if ((height>0) && (kg>0)) {
|
|
double bmi=kg/(height * height);
|
|
ui->BMI->display(bmi);
|
|
ui->BMI->setVisible(true);
|
|
|
|
journal->settings[Journal_BMI]=bmi;
|
|
if (mainwin->getOverview()) {
|
|
g=mainwin->getOverview()->graphView()->findGraph(STR_GRAPH_BMI);
|
|
if (g) g->setDay(nullptr);
|
|
}
|
|
}
|
|
journal->SetChanged(true);
|
|
|
|
// shouldn't be needed anymore with new overview model
|
|
//if (mainwin->getOverview()) mainwin->getOverview()->ResetGraph(STR_GRAPH_Weight);
|
|
}
|
|
|
|
QString Daily::GetDetailsText()
|
|
{
|
|
webView->triggerPageAction(QWebPage::SelectAll);
|
|
QString text=webView->page()->selectedText();
|
|
webView->triggerPageAction(QWebPage::MoveToEndOfDocument);
|
|
webView->triggerPageAction(QWebPage::SelectEndOfDocument);
|
|
return text;
|
|
}
|
|
|
|
void Daily::on_graphCombo_activated(int index)
|
|
{
|
|
if (index<0)
|
|
return;
|
|
|
|
gGraph *g;
|
|
QString s;
|
|
s=ui->graphCombo->currentText();
|
|
bool b=!ui->graphCombo->itemData(index,Qt::UserRole).toBool();
|
|
ui->graphCombo->setItemData(index,b,Qt::UserRole);
|
|
if (b) {
|
|
ui->graphCombo->setItemIcon(index,*icon_on);
|
|
} else {
|
|
ui->graphCombo->setItemIcon(index,*icon_off);
|
|
}
|
|
g=GraphView->findGraphTitle(s);
|
|
g->setVisible(b);
|
|
|
|
updateCube();
|
|
GraphView->updateScale();
|
|
GraphView->redraw();
|
|
}
|
|
void Daily::updateCube()
|
|
{
|
|
//brick..
|
|
if ((GraphView->visibleGraphs()==0)) {
|
|
ui->toggleGraphs->setArrowType(Qt::UpArrow);
|
|
ui->toggleGraphs->setToolTip(tr("Show all graphs"));
|
|
ui->toggleGraphs->blockSignals(true);
|
|
ui->toggleGraphs->setChecked(true);
|
|
ui->toggleGraphs->blockSignals(false);
|
|
|
|
|
|
if (ui->graphCombo->count() > 0) {
|
|
GraphView->setEmptyText(STR_Empty_NoGraphs);
|
|
} else {
|
|
if (!p_profile->GetGoodDay(getDate(), MT_CPAP)
|
|
&& !p_profile->GetGoodDay(getDate(), MT_OXIMETER)
|
|
&& !p_profile->GetGoodDay(getDate(), MT_SLEEPSTAGE)
|
|
&& !p_profile->GetGoodDay(getDate(), MT_POSITION)) {
|
|
GraphView->setEmptyText(STR_Empty_NoData);
|
|
|
|
} else {
|
|
if (GraphView->emptyText() != STR_Empty_Brick)
|
|
GraphView->setEmptyText(STR_Empty_SummaryOnly);
|
|
}
|
|
}
|
|
} else {
|
|
ui->toggleGraphs->setArrowType(Qt::DownArrow);
|
|
ui->toggleGraphs->setToolTip(tr("Hide all graphs"));
|
|
ui->toggleGraphs->blockSignals(true);
|
|
ui->toggleGraphs->setChecked(false);
|
|
ui->toggleGraphs->blockSignals(false);
|
|
}
|
|
}
|
|
|
|
|
|
void Daily::on_toggleGraphs_clicked(bool checked)
|
|
{
|
|
QString s;
|
|
QIcon *icon=checked ? icon_off : icon_on;
|
|
for (int i=0;i<ui->graphCombo->count();i++) {
|
|
s=ui->graphCombo->itemText(i);
|
|
ui->graphCombo->setItemIcon(i,*icon);
|
|
ui->graphCombo->setItemData(i,!checked,Qt::UserRole);
|
|
}
|
|
for (int i=0;i<GraphView->size();i++) {
|
|
(*GraphView)[i]->setVisible(!checked);
|
|
}
|
|
|
|
updateCube();
|
|
GraphView->updateScale();
|
|
GraphView->redraw();
|
|
|
|
}
|
|
|
|
void Daily::updateGraphCombo()
|
|
{
|
|
ui->graphCombo->clear();
|
|
gGraph *g;
|
|
|
|
for (int i=0;i<GraphView->size();i++) {
|
|
g=(*GraphView)[i];
|
|
if (g->isEmpty()) continue;
|
|
|
|
|
|
if (g->visible()) {
|
|
ui->graphCombo->addItem(*icon_on,g->title(),true);
|
|
} else {
|
|
ui->graphCombo->addItem(*icon_off,g->title(),false);
|
|
}
|
|
}
|
|
ui->graphCombo->setCurrentIndex(0);
|
|
|
|
|
|
updateCube();
|
|
}
|
|
|
|
void Daily::on_eventsCombo_activated(int index)
|
|
{
|
|
if (index<0)
|
|
return;
|
|
|
|
|
|
ChannelID code = ui->eventsCombo->itemData(index, Qt::UserRole).toUInt();
|
|
schema::Channel * chan = &schema::channel[code];
|
|
|
|
bool b = !chan->enabled();
|
|
chan->setEnabled(b);
|
|
|
|
ui->eventsCombo->setItemIcon(index,b ? *icon_on : *icon_off);
|
|
|
|
GraphView->redraw();
|
|
}
|
|
|
|
void Daily::on_toggleEvents_clicked(bool checked)
|
|
{
|
|
QString s;
|
|
QIcon *icon=checked ? icon_on : icon_off;
|
|
|
|
ui->toggleEvents->setArrowType(checked ? Qt::DownArrow : Qt::UpArrow);
|
|
ui->toggleEvents->setToolTip(checked ? tr("Hide all events") : tr("Show all events"));
|
|
// ui->toggleEvents->blockSignals(true);
|
|
// ui->toggleEvents->setChecked(false);
|
|
// ui->toggleEvents->blockSignals(false);
|
|
|
|
for (int i=0;i<ui->eventsCombo->count();i++) {
|
|
// s=ui->eventsCombo->itemText(i);
|
|
ui->eventsCombo->setItemIcon(i,*icon);
|
|
ChannelID code = ui->eventsCombo->itemData(i).toUInt();
|
|
schema::channel[code].setEnabled(checked);
|
|
}
|
|
|
|
updateCube();
|
|
GraphView->redraw();
|
|
}
|
|
|
|
//void Daily::on_sessionWidget_itemSelectionChanged()
|
|
//{
|
|
// int row = ui->sessionWidget->currentRow();
|
|
// QTableWidgetItem *item = ui->sessionWidget->item(row, 0);
|
|
// if (item) {
|
|
// QDate date = item->data(Qt::UserRole).toDate();
|
|
// LoadDate(date);
|
|
// qDebug() << "Clicked.. changing date to" << date;
|
|
|
|
// // ui->sessionWidget->setCurrentItem(item);
|
|
// }
|
|
//}
|
|
|
|
void Daily::on_splitter_2_splitterMoved(int, int)
|
|
{
|
|
int size = ui->splitter_2->sizes()[0];
|
|
if (size == 0) return;
|
|
p_profile->appearance->setDailyPanelWidth(size);
|
|
}
|