diff --git a/oscar/daily.cpp b/oscar/daily.cpp
index 321595bd..44d7b204 100644
--- a/oscar/daily.cpp
+++ b/oscar/daily.cpp
@@ -29,6 +29,7 @@
#include "daily.h"
#include "ui_daily.h"
+#include "dailySearchTab.h"
#include "common_gui.h"
#include "SleepLib/profiles.h"
@@ -542,6 +543,7 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
// qDebug() << "Finished making new Daily object";
// sleep(3);
saveGraphLayoutSettings=nullptr;
+ dailySearchTab = new DailySearchTab(this,ui->searchTab,ui->tabWidget);
}
Daily::~Daily()
@@ -565,6 +567,7 @@ Daily::~Daily()
delete icon_on;
delete icon_off;
if (saveGraphLayoutSettings!=nullptr) delete saveGraphLayoutSettings;
+ delete dailySearchTab;
}
void Daily::showEvent(QShowEvent *)
diff --git a/oscar/daily.h b/oscar/daily.h
index 5cac0477..a273de61 100644
--- a/oscar/daily.h
+++ b/oscar/daily.h
@@ -36,6 +36,7 @@ namespace Ui {
}
class MainWindow;
+class DailySearchTab;
/*! \class Daily
@@ -315,9 +316,10 @@ private:
void setGraphText();
void setFlagText();
+ DailySearchTab* dailySearchTab = nullptr;
- QString getLeftAHI (Day * day);
+ //QString getLeftAHI (Day * day);
QString getSessionInformation(Day *);
QString getMachineSettings(Day *);
QString getStatisticsInfo(Day *);
@@ -325,7 +327,7 @@ private:
QString getOximeterInformation(Day *);
QString getEventBreakdown(Day *);
QString getPieChart(float values, Day *);
- QString getIndicesAndPie(Day *, float hours, bool isBrick);
+ //QString getIndicesAndPie(Day *, float hours, bool isBrick);
QString getSleepTime(Day *);
QString getLeftSidebar (bool honorPieChart);
diff --git a/oscar/daily.ui b/oscar/daily.ui
index 9dd0ad79..284d91f0 100644
--- a/oscar/daily.ui
+++ b/oscar/daily.ui
@@ -1402,6 +1402,11 @@ QSlider::handle:horizontal {
+
+
+ Search
+
+
diff --git a/oscar/dailySearchTab.cpp b/oscar/dailySearchTab.cpp
new file mode 100644
index 00000000..262d90d3
--- /dev/null
+++ b/oscar/dailySearchTab.cpp
@@ -0,0 +1,868 @@
+/* user graph settings Implementation
+ *
+ * Copyright (c) 2019-2022 The OSCAR Team
+ * Copyright (c) 2011-2018 Mark Watkins
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of the source code
+ * for more details. */
+
+
+#define TEST_MACROS_ENABLEDoff
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "dailySearchTab.h"
+#include "SleepLib/day.h"
+#include "SleepLib/profiles.h"
+#include "daily.h"
+
+
+#define OT_NONE 0
+#define OT_DISABLED_SESSIONS 1
+#define OT_NOTES 2
+#define OT_NOTES_STRING 3
+#define OT_BOOK_MARKS 4
+#define OT_AHI 5
+#define OT_SHORT_SESSIONS 6
+#define OT_SESSIONS_QTY 7
+#define OT_DAILY_USAGE 8
+
+DailySearchTab::DailySearchTab(Daily* daily , QWidget* searchTabWidget , QTabWidget* dailyTabWidget) :
+ daily(daily) , parent(daily) , searchTabWidget(searchTabWidget) ,dailyTabWidget(dailyTabWidget)
+{
+ icon_on = new QIcon(":/icons/session-on.png");
+ icon_off = new QIcon(":/icons/session-off.png");
+
+
+ #if 0
+ // method of find the daily tabWidgets works for english.
+ // the question will it work for all other langauges???
+ // Right now they are const int in the header file.
+ int maxIndex = dailyTabWidget->count();
+ for (int index=0 ; indextabText(index);
+ if (title.contains("detail",Qt::CaseInsensitive) ) {TW_DETAILED = index; continue;};
+ if (title.contains("event",Qt::CaseInsensitive) ) {TW_EVENTS = index; continue;};
+ if (title.contains("note",Qt::CaseInsensitive) ) {TW_NOTES = index; continue;};
+ if (title.contains("bookmark",Qt::CaseInsensitive) ) {TW_BOOKMARK = index; continue;};
+ if (title.contains("search",Qt::CaseInsensitive) ) {TW_SEARCH = index; continue;};
+ }
+ #endif
+
+ createUi();
+ daily->connect(enterString, SIGNAL(textEdited(QString)), this, SLOT(on_textEdited(QString)) );
+ daily->connect(enterInteger, SIGNAL(valueChanged(int)), this, SLOT(on_intValueChanged(int)) );
+ daily->connect(enterDouble, SIGNAL(valueChanged(double)), this, SLOT(on_doubleValueChanged(double)) );
+ daily->connect(startButton, SIGNAL(clicked()), this, SLOT(on_startButton_clicked()) );
+ daily->connect(continueButton, SIGNAL(clicked()), this, SLOT(on_continueButton_clicked()) );
+ //daily->connect(guiDisplayTable, SIGNAL(itemActivated(QTableWidgetItem*)), this, SLOT(on_itemActivated(QTableWidgetItem*) ));
+ daily->connect(guiDisplayTable, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(on_itemActivated(QTableWidgetItem*) ));
+ daily->connect(guiDisplayTable, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(on_itemActivated(QTableWidgetItem*) ));
+ daily->connect(selectCommand, SIGNAL(activated(int)), this, SLOT(on_selectCommand_activated(int) ));
+ daily->connect(dailyTabWidget, SIGNAL(currentChanged(int)), this, SLOT(on_dailyTabWidgetCurrentChanged(int) ));
+}
+
+DailySearchTab::~DailySearchTab() {
+ daily->disconnect(enterString, SIGNAL(textEdited(QString)), this, SLOT(on_textEdited(QString)) );
+ daily->disconnect(dailyTabWidget, SIGNAL(currentChanged(int)), this, SLOT(on_dailyTabWidgetCurrentChanged(int) ));
+ daily->disconnect(enterInteger, SIGNAL(valueChanged(int)), this, SLOT(on_intValueChanged(int)) );
+ daily->disconnect(enterDouble, SIGNAL(valueChanged(double)), this, SLOT(on_doubleValueChanged(double)) );
+ daily->disconnect(selectCommand, SIGNAL(activated(int)), this, SLOT(on_selectCommand_activated(int) ));
+ //daily->disconnect(guiDisplayTable, SIGNAL(itemActivated(QTableWidgetItem*)), this, SLOT(on_itemActivated(QTableWidgetItem*) ));
+ daily->disconnect(guiDisplayTable, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(on_itemActivated(QTableWidgetItem*) ));
+ daily->disconnect(guiDisplayTable, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(on_itemActivated(QTableWidgetItem*) ));
+ daily->disconnect(continueButton, SIGNAL(clicked()), this, SLOT(on_continueButton_clicked()) );
+ daily->disconnect(startButton, SIGNAL(clicked()), this, SLOT(on_startButton_clicked()) );
+ delete icon_on ;
+ delete icon_off ;
+};
+
+void DailySearchTab::createUi() {
+
+ QFont baseFont =*defaultfont;
+ baseFont.setPointSize(1+baseFont.pointSize());
+ searchTabWidget ->setFont(baseFont);
+
+ searchTabLayout = new QVBoxLayout(searchTabWidget);
+ criteriaLayout = new QHBoxLayout();
+ searchLayout = new QHBoxLayout();
+ statusLayout = new QHBoxLayout();
+ summaryLayout = new QHBoxLayout();
+ searchTabLayout ->setObjectName(QString::fromUtf8("verticalLayout_21"));
+ searchTabLayout ->setContentsMargins(4, 4, 4, 4);
+
+ introduction = new QLabel(this);
+ selectLabel = new QLabel(this);
+ selectCommand = new QComboBox(this);
+ startButton = new QPushButton(this);
+ continueButton = new QPushButton(this);
+ guiDisplayTable = new QTableWidget(this);
+ enterDouble = new QDoubleSpinBox(this);
+ enterInteger = new QSpinBox(this);
+ enterString = new QLineEdit(this);
+ criteriaOperation = new QLabel(this);
+ statusA = new QLabel(this);
+ statusB = new QLabel(this);
+ statusC = new QLabel(this);
+ summaryStatsA = new QLabel(this);
+ summaryStatsB = new QLabel(this);
+ summaryStatsC = new QLabel(this);
+
+ searchTabLayout ->addWidget(introduction);
+
+ criteriaLayout ->addWidget(selectLabel);
+ criteriaLayout ->insertStretch(1,5);
+ criteriaLayout ->addWidget(selectCommand);
+ criteriaLayout ->addWidget(criteriaOperation);
+ criteriaLayout ->addWidget(enterInteger);
+ criteriaLayout ->addWidget(enterString);
+ criteriaLayout ->addWidget(enterDouble);
+ criteriaLayout ->insertStretch(-1,5);
+ searchTabLayout ->addLayout(criteriaLayout);
+
+
+ searchLayout ->addWidget(startButton);
+ searchLayout ->addWidget(continueButton);
+ searchTabLayout ->addLayout(searchLayout);
+
+ statusLayout ->insertStretch(0,1);
+ statusLayout ->addWidget(statusA);
+ statusLayout ->addWidget(statusB);
+ statusLayout ->addWidget(statusC);
+ statusLayout ->insertStretch(-1,1);
+ searchTabLayout ->addLayout(statusLayout);
+
+ summaryLayout ->addWidget(summaryStatsA);
+ summaryLayout ->addWidget(summaryStatsB);
+ summaryLayout ->addWidget(summaryStatsC);
+ searchTabLayout ->addLayout(summaryLayout);
+
+ DEBUGFW ;
+
+
+ // searchTabLayout ->addWidget(guiDisplayList);
+ searchTabLayout ->addWidget(guiDisplayTable);
+
+ DEBUGFW ;
+
+ searchTabWidget ->setFont(baseFont);
+ guiDisplayTable->setFont(baseFont);
+ guiDisplayTable->setColumnCount(2);
+ guiDisplayTable->setObjectName(QString::fromUtf8("guiDisplayTable"));
+ //guiDisplayTable->setAlternatingRowColors(true);
+ guiDisplayTable->setSelectionMode(QAbstractItemView::SingleSelection);
+ guiDisplayTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ guiDisplayTable->setSortingEnabled(true);
+ QHeaderView* horizontalHeader = guiDisplayTable->horizontalHeader();
+ QHeaderView* verticalHeader = guiDisplayTable->verticalHeader();
+ horizontalHeader->setStretchLastSection(true);
+ horizontalHeader->setVisible(false);
+ horizontalHeader->setSectionResizeMode(QHeaderView::Stretch);
+ //guiDisplayTable->horizontalHeader()->setDefaultSectionSize(QFontMetrics(baseFont).height());
+ verticalHeader->setVisible(false);
+ verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
+ verticalHeader->setDefaultSectionSize(24);
+
+ introduction ->setText(introductionStr());
+ introduction ->setFont(baseFont);
+ statusA ->show();
+ //statusB ->show();
+ //statusC ->show();
+ summaryStatsA ->setFont(baseFont);
+ summaryStatsB ->setFont(baseFont);
+ summaryStatsC ->setFont(baseFont);
+ summaryStatsA ->show();
+ summaryStatsB ->show();
+ summaryStatsC ->show();
+ enterDouble ->hide();
+ enterInteger ->hide();
+ enterString ->hide();
+
+ enterString->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
+ enterDouble->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
+ enterInteger->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
+ selectCommand->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
+
+ startButton->setObjectName(QString::fromUtf8("startButton"));
+ startButton->setText(tr("Start Search"));
+ continueButton->setObjectName(QString::fromUtf8("continueButton"));
+ continueButton->setText(tr("Continue Search"));
+ continueButton->setEnabled(false);
+ startButton->setEnabled(false);
+
+ selectCommand->setObjectName(QString::fromUtf8("selectCommand"));
+ selectCommand->setFont(baseFont);
+}
+
+void DailySearchTab::delayedCreateUi() {
+ // meed delay to insure days are populated.
+ if (createUiFinished) return;
+
+ #if 0
+ // to change alignment of a combo box
+ selectCommand->setEditable(true);
+ QLineEdit* lineEdit = selectCommand->lineEdit();
+ lineEdit->setAlignment(Qt::AlignCenter);
+ if (lineEdit) {
+ lineEdit->setReadOnly(true);
+ }
+ #endif
+
+ createUiFinished = true;
+ selectLabel->setText(tr("Match:"));
+
+ selectCommand->clear();
+ selectCommand->addItem(tr("Select Match"),OT_NONE);
+ selectCommand->insertSeparator(selectCommand->count());
+ selectCommand->addItem(tr("Notes"),OT_NOTES);
+ selectCommand->addItem(tr("Notes containng"),OT_NOTES_STRING);
+ selectCommand->addItem(tr("BookMarks"),OT_BOOK_MARKS);
+ selectCommand->addItem(tr("Disabled Sessions"),OT_DISABLED_SESSIONS);
+ selectCommand->addItem(tr("Session Duration" ),OT_SHORT_SESSIONS);
+ selectCommand->addItem(tr("Number of Sessions"),OT_SESSIONS_QTY);
+ selectCommand->addItem(tr("Daily Usage"),OT_DAILY_USAGE);
+ selectCommand->addItem(tr("AHI "),OT_AHI);
+ selectCommand->insertSeparator(selectCommand->count());
+ // Now add events
+ QDate date = p_profile->LastDay(MT_CPAP);
+ if ( !date.isValid()) return;
+ Day* day = p_profile->GetDay(date);
+ if (!day) return;
+ // the following is copied from daily.
+ quint32 chans = schema::SPAN | schema::FLAG | schema::MINOR_FLAG;
+ if (p_profile->general->showUnknownFlags()) chans |= schema::UNKNOWN;
+ QList available;
+ available.append(day->getSortedMachineChannels(chans));
+ for (int i=0; i < available.size(); ++i) {
+ ChannelID id = available.at(i);
+ schema::Channel chan = schema::channel[ id ];
+ // new stuff now
+ //QString displayName= chan.code();
+ QString displayName= chan.fullname();
+ //QString item = QString("%1 :%2").arg(displayName).arg(tr(""));
+ selectCommand->addItem(displayName,id);
+ }
+}
+
+void DailySearchTab::selectAligment(bool withParameters) {
+ if (withParameters) {
+ // operand is right justified and value is left justified.
+ } {
+ // only operand and it is centered.
+ }
+}
+
+void DailySearchTab::on_selectCommand_activated(int index) {
+ int item = selectCommand->itemData(index).toInt();
+ enterDouble->hide();
+ enterDouble->setDecimals(3);
+ enterInteger->hide();
+ enterString->hide();
+ criteriaOperation->hide();
+ minMaxValid = false;
+ minMaxMode = none;
+ minMaxUnit = noUnit;
+ minMaxInteger=0;
+ minMaxDouble=0.0;
+
+ searchType = OT_NONE;
+ switch (item) {
+ case OT_NONE :
+ break;
+ case OT_DISABLED_SESSIONS :
+ searchType = item;
+ break;
+ case OT_NOTES :
+ searchType = item;
+ break;
+ case OT_BOOK_MARKS :
+ searchType = item;
+ break;
+ case OT_NOTES_STRING :
+ searchType = item;
+ enterString->clear();
+ enterString->show();
+ criteriaOperation->setText(QChar(0x2208)); // use either 0x220B or 0x2208
+ criteriaOperation->show();
+ break;
+ case OT_AHI :
+ searchType = item;
+ enterDouble->setRange(0,999);
+ enterDouble->setValue(5.0);
+ enterDouble->setDecimals(2);
+ criteriaOperation->setText(">");
+ criteriaOperation->show();
+ enterDouble->show();
+ minMaxMode = maxDouble;
+ break;
+ case OT_SHORT_SESSIONS :
+ searchType = item;
+ enterDouble->setRange(0,2000);
+ enterDouble->setSuffix(" Miniutes");
+ enterDouble->setDecimals(2);
+ criteriaOperation->setText("<");
+ criteriaOperation->show();
+ enterDouble->setValue(5);
+ enterDouble->show();
+ minMaxUnit = time;
+ minMaxMode = minInteger;
+ break;
+ case OT_SESSIONS_QTY :
+ searchType = item;
+ enterInteger->setRange(0,99);
+ enterInteger->setSuffix("");
+ enterInteger->setValue(1);
+ criteriaOperation->setText(">");
+ criteriaOperation->show();
+ minMaxMode = maxInteger;
+ enterInteger->show();
+ break;
+ case OT_DAILY_USAGE :
+ searchType = item;
+ enterDouble->setRange(0,999);
+ enterDouble->setSuffix(" Hours");
+ enterDouble->setDecimals(2);
+ criteriaOperation->setText("<");
+ criteriaOperation->show();
+ enterDouble->setValue(p_profile->cpap->complianceHours());
+ enterDouble->show();
+ minMaxUnit = time;
+ minMaxMode = minInteger;
+ break;
+ default:
+ // Have an Event
+ enterInteger->setRange(0,999);
+ enterInteger->setSuffix("");
+ enterInteger->setValue(0);
+ criteriaOperation->setText(">");
+ criteriaOperation->show();
+ minMaxMode = maxInteger;
+ enterInteger->show();
+ searchType = item; //item is channel id which is >= 0x1000
+ break;
+ }
+ criteriaChanged();
+ if (searchType == OT_NONE) {
+ statusA->show();
+ statusA->setText(centerLine("Please select a Match"));
+ //statusB->hide();
+ summaryStatsA->clear();
+ summaryStatsB->clear();
+ summaryStatsC->clear();
+ continueButton->setEnabled(false);
+ startButton->setEnabled(false);
+ return;
+ }
+
+}
+
+
+bool DailySearchTab::find(QDate& date,Day* day)
+{
+ if (!day) return false;
+ bool found=false;
+ QString extra="";
+ switch (searchType) {
+ case OT_DISABLED_SESSIONS :
+ {
+ QList sessions = day->getSessions(MT_CPAP,true);
+ for (auto & sess : sessions) {
+ if (!sess->enabled()) {
+ found=true;
+ nextTab = TW_DETAILED ;
+ }
+ }
+ }
+ break;
+ case OT_NOTES :
+ {
+ Session* journal=daily->GetJournalSession(date);
+ if (journal && journal->settings.contains(Journal_Notes)) {
+ QString jcontents = convertRichText2Plain(journal->settings[Journal_Notes].toString());
+ extra = jcontents.trimmed().left(20);
+ found=true;
+ nextTab = TW_NOTES ;
+ }
+ }
+ break;
+ case OT_BOOK_MARKS :
+ {
+ Session* journal=daily->GetJournalSession(date);
+ if (journal && journal->settings.contains(Bookmark_Start)) {
+ found=true;
+ nextTab = TW_BOOKMARK ;
+ }
+ }
+ break;
+ case OT_NOTES_STRING :
+ {
+ Session* journal=daily->GetJournalSession(date);
+ if (journal && journal->settings.contains(Journal_Notes)) {
+ QString jcontents = convertRichText2Plain(journal->settings[Journal_Notes].toString());
+ QString findStr = enterString->text();
+ if (jcontents.contains(findStr,Qt::CaseInsensitive) ) {
+ found=true;
+ extra = jcontents.trimmed().left(20);
+ nextTab = TW_NOTES ;
+ }
+ }
+ }
+ break;
+ case OT_AHI :
+ {
+ EventDataType ahi = calculateAhi(day);
+ EventDataType limit = enterDouble->value();
+ if (!minMaxValid || ahi > minMaxDouble ) {
+ minMaxDouble = ahi;
+ minMaxValid = true;
+ }
+ if (ahi > limit ) {
+ found=true;
+ nextTab = TW_EVENTS ;
+ nextTab = TW_DETAILED ;
+ extra = QString::number(ahi,'f', 2);
+ }
+ }
+ break;
+ case OT_SHORT_SESSIONS :
+ {
+ QList sessions = day->getSessions(MT_CPAP);
+ for (auto & sess : sessions) {
+ qint64 ms = sess->length();
+ double minutes= ((double)ms)/60000.0;
+ if (!minMaxValid || ms < minMaxInteger ) {
+ minMaxInteger = ms;
+ minMaxValid = true;
+ }
+ if (minutes < enterDouble->value()) {
+ found=true;
+ nextTab = TW_DETAILED ;
+ extra = formatTime(ms);
+ }
+ }
+ }
+ break;
+ case OT_SESSIONS_QTY :
+ {
+ QList sessions = day->getSessions(MT_CPAP);
+ quint32 size = sessions.size();
+ if (!minMaxValid || size > minMaxInteger ) {
+ minMaxInteger = size;
+ minMaxValid = true;
+ }
+ if (size > (quint32)enterInteger->value()) {
+ found=true;
+ nextTab = TW_DETAILED ;
+ extra = QString::number(size);
+ }
+ }
+ break;
+ case OT_DAILY_USAGE :
+ {
+ QList sessions = day->getSessions(MT_CPAP);
+ qint64 sum = 0 ;
+ for (auto & sess : sessions) {
+ sum += sess->length();
+ }
+ double hours= ((double)sum)/3600000.0;
+ if (!minMaxValid || sum < minMaxInteger ) {
+ minMaxInteger = sum;
+ minMaxValid = true;
+ }
+ if (hours < enterDouble->value()) {
+ found=true;
+ nextTab = TW_DETAILED ;
+ extra = formatTime(sum);
+ }
+ }
+ break;
+ default :
+ {
+ quint32 count = day->count(searchType);
+ if (count<=0) break;
+ //DEBUGFW Q(count) Q(minMaxInteger) Q(minMaxValid) ;
+ if (!minMaxValid || (quint32)count > minMaxInteger ) {
+ //DEBUGFW Q(count) Q(minMaxInteger) Q(minMaxValid) ;
+ minMaxInteger = count;
+ minMaxValid = true;
+ }
+ if (count > (quint32) enterInteger->value()) {
+ found=true;
+ extra = QString::number(count);
+ nextTab = TW_EVENTS ;
+ }
+ }
+ break;
+ case OT_NONE :
+ return false;
+ break;
+ }
+ if (found) {
+ addItem(date , extra );
+ return true;
+ }
+ return false;
+};
+
+void DailySearchTab::findall(QDate date, bool start)
+{
+ Q_UNUSED(start);
+ guiDisplayTable->clear();
+ passFound=0;
+ int count = 0;
+ int no_data = 0;
+ Day*day;
+ while (true) {
+ count++;
+ nextDate = date;
+ if (passFound >= passDisplayLimit) {
+ break;
+ }
+ if (date < firstDate) {
+ break;
+ }
+ if (date > lastDate) {
+ break;
+ }
+ daysSearched++;
+ if (date.isValid()) {
+ // use date
+ // find and add
+ //daysSearched++;
+ day= p_profile->GetDay(date);
+ if (day) {
+ if (find(date, day) ) {
+ passFound++;
+ daysFound++;
+ }
+ } else {
+ no_data++;
+ daysSkipped++;
+ // Skip day. maybe no sleep or sdcard was no inserted.
+ }
+ } else {
+ qWarning() << "DailySearchTab::findall invalid date." << date;
+ break;
+ }
+ date=date.addDays(-1);
+ }
+ endOfPass();
+ return ;
+
+};
+
+void DailySearchTab::addItem(QDate date, QString value) {
+ int row = passFound;
+
+ QTableWidgetItem *item = new QTableWidgetItem(*icon_off,date.toString());
+ item->setData(dateRole,date);
+ item->setData(valueRole,value);
+ item->setIcon (*icon_off);
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+ QTableWidgetItem *item2 = new QTableWidgetItem(value);
+ item2->setTextAlignment(Qt::AlignCenter);
+ //item2->setData(dateRole,date);
+ //item2->setData(valueRole,value);
+ item2->setFlags(Qt::NoItemFlags);
+ if (guiDisplayTable->rowCount()<(row+1)) {
+ guiDisplayTable->insertRow(row);
+ }
+
+ guiDisplayTable->setItem(row,0,item);
+ guiDisplayTable->setItem(row,1,item2);
+}
+
+void DailySearchTab::endOfPass() {
+ QString display;
+ if ((passFound >= passDisplayLimit) && (daysSearchedsetText(centerLine(tr("More to Search")));
+ //statusB->setText("");
+ //statusC->setText(centerLine(tr("Continue or Change Match")));
+ statusA->show();
+ //statusB->hide();
+ //statusC->show();
+
+
+
+ continueButton->setEnabled(true);
+ startButton->setEnabled(false);
+ } else if (daysFound>0) {
+ DEBUGFW ;
+ statusA->setText(centerLine(tr("End of Search")));
+ //statusB->setText("");
+ //statusC->setText(centerLine(tr("Change Match")));
+ statusA->show();
+ //statusB->hide();
+ //statusC->show();
+
+ continueButton->setEnabled(false);
+ startButton->setEnabled(false);
+ } else {
+ DEBUGFW ;
+ statusA->setText(centerLine(tr("No Matching Criteria")));
+ //statusB->setText("");
+ //statusC->setText(centerLine(tr("Change Match")));
+ statusA->show();
+ //statusB->hide();
+ //statusC->show();
+ continueButton->setEnabled(false);
+ }
+
+ //status->setText(centerLine( display ));
+ //status->show();
+ displayStatistics();
+}
+
+
+void DailySearchTab::search(QDate date, bool start)
+{
+ findall(date,start);
+};
+
+
+void DailySearchTab::on_itemActivated(QTableWidgetItem *item)
+{
+ if (item->column()!=0) {
+ item=guiDisplayTable->item(item->row(),0);
+ }
+ QDate date = item->data(dateRole).toDate();
+ item->setIcon (*icon_on);
+ guiDisplayTable->setCurrentItem(item,QItemSelectionModel::Clear);
+ daily->LoadDate( date );
+ if (nextTab>=0 && nextTab < dailyTabWidget->count()) {
+ dailyTabWidget->setCurrentIndex(nextTab); // 0 = details ; 1=events =2 notes ; 3=bookarks;
+ }
+}
+
+void DailySearchTab::on_continueButton_clicked()
+{
+ search (nextDate , false);
+}
+
+void DailySearchTab::on_startButton_clicked()
+{
+ firstDate = p_profile->FirstDay(MT_CPAP);
+ lastDate = p_profile->LastDay(MT_CPAP);
+ daysTotal= 1+firstDate.daysTo(lastDate);
+ daysFound=0;
+ daysSkipped=0;
+ daysSearched=0;
+
+ search (lastDate ,true);
+
+}
+
+void DailySearchTab::on_intValueChanged(int ) {
+ enterInteger->findChild()->deselect();
+ criteriaChanged();
+}
+
+void DailySearchTab::on_doubleValueChanged(double ) {
+ enterDouble->findChild()->deselect();
+ criteriaChanged();
+}
+
+void DailySearchTab::on_textEdited(QString ) {
+ criteriaChanged();
+}
+
+void DailySearchTab::on_dailyTabWidgetCurrentChanged(int ) {
+ delayedCreateUi();
+}
+
+void DailySearchTab::displayStatistics() {
+ QString extra;
+ QString space("");
+ if (minMaxValid)
+ switch (minMaxMode) {
+ case minInteger:
+ if (minMaxUnit == time) {
+ extra = QString("%1%2%3").arg(space).arg(tr("Min: ")).arg( formatTime(minMaxInteger));
+ } else {
+ extra = QString("%1%2%3").arg(space).arg(tr("Min: ")).arg(minMaxInteger);
+ }
+ break;
+ case maxInteger:
+ extra = QString("%1%2%3").arg(space).arg(tr("Max: ")).arg(minMaxInteger);
+ break;
+ case minDouble:
+ extra = QString("%1%2%3").arg(space).arg(tr("Min: ")).arg(minMaxDouble,0,'f',1);
+ break;
+ case maxDouble:
+ extra = QString("%1%2%3").arg(space).arg(tr("Max: ")).arg(minMaxDouble,0,'f',1);
+ break;
+ default:
+ extra="";
+ break;
+ }
+ summaryStatsA->setText(centerLine(QString(tr("Searched %1/%2 days.")).arg(daysSearched).arg(daysTotal) ));
+ summaryStatsB->setText(centerLine(QString(tr("Found %1.")).arg(daysFound) ));
+ if (extra.size()>0) {
+ summaryStatsC->setText(extra);
+ summaryStatsC->show();
+ } else {
+ summaryStatsC->hide();
+ }
+
+}
+
+void DailySearchTab::criteriaChanged() {
+ statusA->setText(centerLine(" ----- "));
+ statusA->clear();
+ statusB->clear();
+ statusC->clear();
+ summaryStatsA->clear();
+ summaryStatsB->clear();
+ summaryStatsC->clear();
+ startButton->setEnabled( true);
+ continueButton->setEnabled(false);
+ guiDisplayTable->clear();
+}
+
+// inputs character string.
+// outputs cwa centered html string.
+// converts \n to
+QString DailySearchTab::centerLine(QString line) {
+ return QString( "%1").arg(line).replace("\n","
");
+}
+
+QString DailySearchTab::introductionStr() {
+ return centerLine(
+ "Finds days that match specified criteria\n"
+ "Searches from last day to first day\n"
+ "-----\n"
+ "Find Days with:"
+ );
+ //"Searching starts on the lastDay to the firstDay\n"
+}
+
+QString DailySearchTab::formatTime (quint32 ms) {
+ DEBUGFW Q(ms) ;
+ ms += 500; // round to nearest second
+ DEBUGFW Q(ms) ;
+ quint32 hours = ms / 3600000;
+ ms = ms % 3600000;
+ DEBUGFW Q(ms) Q(hours) ;
+ quint32 minutes = ms / 60000;
+ DEBUGFW Q(ms) Q(hours) Q(minutes) ;
+ ms = ms % 60000;
+ quint32 seconds = ms /1000;
+ DEBUGFW Q(ms) Q(hours) Q(minutes) Q(seconds);
+ return QString("%1h %2m %3s").arg(hours).arg(minutes).arg(seconds);
+ #if 0
+ double seconds = minutes*60;
+ if (seconds<100) {
+ //display seconds
+ } else {
+ // display tenths of minutes.
+ return QString("%1 minutes").arg(seconds,0,'f',1);
+ }
+ #endif
+}
+
+QString DailySearchTab::convertRichText2Plain (QString rich) {
+ richText.setHtml(rich);
+ return richText.toPlainText();
+}
+
+EventDataType DailySearchTab::calculateAhi(Day* day) {
+ if (!day) return 0.0;
+ double tmphours=day->hours(MT_CPAP);
+ if (tmphours<=0) return 0;
+ EventDataType ahi=day->count(AllAhiChannels);
+ if (p_profile->general->calculateRDI()) ahi+=day->count(CPAP_RERA);
+ ahi/=tmphours;
+ return ahi;
+}
+
+
+#if 0
+
+
+ quint32 chantype = schema::FLAG | schema::SPAN | schema::MINOR_FLAG;
+ if (p_profile->general->showUnknownFlags()) chantype |= schema::UNKNOWN;
+ QList chans = day->getSortedMachineChannels(chantype);
+
+ // Go through all the enabled sessions of the day
+ for (QList::iterator s=day->begin();s!=day->end();++s) {
+ Session * sess = *s;
+ if (!sess->enabled()) continue;
+
+ // For each session, go through all the channels
+ QHash >::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;
+
+ // Prepare title for this code, if there are any events
+ 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];
+ }
+
+ // number of digits required for count depends on total for day
+ int numDigits = ceil(log10(day->count(code)+1));
+
+ // Now we go through the event list for the *session* (not for the day)
+ for (int z=0;zraw(o) > 0)
+ s += QString(" (%3)").arg(m.value()[z]->raw(o));
+
+ a.append(s);
+ QTreeWidgetItem *item=new QTreeWidgetItem(a);
+ item->setData(0,Qt::UserRole,t);
+ mcr->addChild(item);
+ }
+ }
+ }
+ }
+
+
+
+#endif
diff --git a/oscar/dailySearchTab.h b/oscar/dailySearchTab.h
new file mode 100644
index 00000000..413cfad3
--- /dev/null
+++ b/oscar/dailySearchTab.h
@@ -0,0 +1,143 @@
+/* search GUI Headers
+ *
+ * Copyright (c) 2019-2022 The OSCAR Team
+ * Copyright (C) 2011-2018 Mark Watkins
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of the source code
+ * for more details. */
+
+#ifndef SEARCHDAILY_H
+#define SEARCHDAILY_H
+
+#include
+#include
+#include
+#include
+#include
+#include "SleepLib/common.h"
+
+class QWidget ;
+class QHBoxLayout ;
+class QVBoxLayout ;
+class QPushButton ;
+class QLabel ;
+class QComboBox ;
+class QDoubleSpinBox ;
+class QSpinBox ;
+class QLineEdit ;
+class QTableWidget ;
+class QTableWidgetItem ;
+
+class Day; //forward declaration.
+class Daily; //forward declaration.
+
+class DailySearchTab : public QWidget
+{
+ Q_OBJECT
+public:
+ DailySearchTab ( Daily* daily , QWidget* , QTabWidget* ) ;
+ ~DailySearchTab();
+
+private:
+
+ // these values are hard coded. because dynamic translation might not do the proper assignment.
+ // Dynamic code is commented out using c preprocess #if #endif
+ const int TW_NONE = -1;
+ const int TW_DETAILED = 0;
+ const int TW_EVENTS = 1;
+ const int TW_NOTES = 2;
+ const int TW_BOOKMARK = 3;
+ const int TW_SEARCH = 4;
+
+
+ const int dateRole = Qt::UserRole;
+ const int valueRole = 1+Qt::UserRole;
+ const int passDisplayLimit = 30;
+
+ Daily* daily;
+ QWidget* parent;
+ QWidget* searchTabWidget;
+ QTabWidget* dailyTabWidget;
+ QVBoxLayout* searchTabLayout;
+ QHBoxLayout* criteriaLayout;
+ QHBoxLayout* searchLayout;
+ QHBoxLayout* statusLayout;
+ QHBoxLayout* summaryLayout;
+ QLabel* criteriaOperation;
+ QLabel* introduction;
+ QComboBox* selectCommand;
+ QLabel* selectLabel;
+ QLabel* statusA;
+ QLabel* statusB;
+ QLabel* statusC;
+ QLabel* summaryStatsA;
+ QLabel* summaryStatsB;
+ QLabel* summaryStatsC;
+ QDoubleSpinBox* enterDouble;
+ QSpinBox* enterInteger;
+ QLineEdit* enterString;
+ QPushButton* startButton;
+ QPushButton* continueButton;
+ QTableWidget* guiDisplayTable;
+ QIcon* icon_on;
+ QIcon* icon_off;
+
+ void createUi();
+ void delayedCreateUi();
+
+ void search(QDate date, bool star);
+ void findall(QDate date, bool start);
+ bool find(QDate& , Day* day);
+ EventDataType calculateAhi(Day* day);
+
+ void selectAligment(bool withParameters);
+ void displayStatistics();
+ void addItem(QDate date, QString value);
+ void criteriaChanged();
+ void endOfPass();
+ QString introductionStr();
+
+ QString centerLine(QString line);
+ QString formatTime (quint32) ;
+ QString convertRichText2Plain (QString rich);
+
+ bool createUiFinished=false;
+ int searchType;
+ int nextTab;
+
+ QDate firstDate ;
+ QDate lastDate ;
+ QDate nextDate;
+
+ //
+ int daysTotal;
+ int daysSkipped;
+ int daysSearched;
+ int daysFound;
+ int passFound;
+
+ enum minMax {none=0,minDouble,maxDouble,minInteger,maxInteger};
+ enum minMaxUnit {noUnit=0,time=1};
+ bool minMaxValid;
+ minMaxUnit minMaxUnit;
+ minMax minMaxMode;
+ quint32 minMaxInteger;
+ double minMaxDouble;
+
+ QTextDocument richText;
+
+public slots:
+private slots:
+ void on_itemActivated(QTableWidgetItem *item);
+ void on_startButton_clicked();
+ void on_continueButton_clicked();
+ void on_selectCommand_activated(int);
+ void on_dailyTabWidgetCurrentChanged(int);
+ void on_intValueChanged(int);
+ void on_doubleValueChanged(double);
+ void on_textEdited(QString);
+};
+
+#endif // SEARCHDAILY_H
+
diff --git a/oscar/oscar.pro b/oscar/oscar.pro
index 12ce9a97..cd8d9ab2 100644
--- a/oscar/oscar.pro
+++ b/oscar/oscar.pro
@@ -255,11 +255,12 @@ lessThan(QT_MAJOR_VERSION,5)|lessThan(QT_MINOR_VERSION,12) {
SOURCES += \
checkupdates.cpp \
+ dailySearchTab.cpp \
+ daily.cpp \
saveGraphLayoutSettings.cpp \
overview.cpp \
common_gui.cpp \
cprogressbar.cpp \
- daily.cpp \
exportcsv.cpp \
main.cpp \
mainwindow.cpp \
@@ -362,11 +363,12 @@ QMAKE_EXTRA_COMPILERS += optimize
HEADERS += \
checkupdates.h \
+ dailySearchTab.h \
+ daily.h \
saveGraphLayoutSettings.h \
overview.h \
common_gui.h \
cprogressbar.h \
- daily.h \
exportcsv.h \
mainwindow.h \
newprofile.h \
diff --git a/oscar/test_macros.h b/oscar/test_macros.h
index b6d4f00e..5fc2ab3d 100644
--- a/oscar/test_macros.h
+++ b/oscar/test_macros.h
@@ -56,8 +56,10 @@ To turn off the the test macros.
//#define Q( VALUE ) << QString("%1:%2").arg( "" #VALUE).arg(VALUE)
//#define QQ( TEXT , EXPRESSION) << QString("%1:%2").arg( "" #TEXT).arg(VALUE)
-#define NAME( SCHEMACODE ) << schema::channel[ SCHEMACODE ].label()
-#define FULLNAME( SCHEMACODE ) << schema::channel[ SCHEMAcODE ].fullname()
+//#define NAME( SCHEMACODE ) << schema::channel[ SCHEMACODE ].label()
+#define NAME( SCHEMACODE ) << QString(("%1:0x%2")).arg(schema::channel[ SCHEMACODE ].label()).arg( QString::number(SCHEMACODE,16).toUpper() )
+#define FULLNAME( SCHEMACODE ) << schema::channel[ SCHEMACODE ].fullname()
+
//display the date of an epoch time stamp "qint64"
#define DATE( EPOCH ) << QDateTime::fromMSecsSinceEpoch( EPOCH ).toString("dd MMM yyyy")
@@ -120,6 +122,48 @@ To turn off the the test macros.
#define DATETIME( XX )
#define COMPILER
-#endif
-#endif
+#endif // TEST_MACROS_ENABLED
+#ifdef TEST_ROUTIMES_ENABLED
+This is prototype
+class testRoutines : public QWidget
+{
+Q_OBJECT
+public:
+typedef enum {debugDisplay = 0, returnQTextEdit} findClassMode;
+QWidget* findQTextEditdisplaywidgets(QWidget* widget,findClassMode mode=findClassMode::debugDisplay,QString name="",int recurseCount=0) {
+ return findQTextEditdisplaywidgets(widget,findClassMode::debugDisplay,"",0);
+}
+private:
+QWidget* findQTextEditdisplaywidgets(QWidget* widget,findClassMode mode,QString objectName,int recurseCount) {
+ QString indent;
+ if (!widget) return nullptr;
+ if (mode==debugDisplay) {
+ if (recurseCount==0) {
+ DEBUGF O("===================================================");
+ }
+ indent = QString("%1").arg("",(recurseCount*4),QLatin1Char(' '));
+ }
+ recurseCount++;
+ if (recurseCount>10) return nullptr;
+ if (mode==debugDisplay) {
+ DEBUGF O(indent) O(widget) ;
+ } else if (mode==returnQTextEdit){
+ if(QTextEdit* te = dynamic_cast(widget)) {
+ return widget ;
+ };
+ }
+ const QList list = widget->children();
+ for (int i = 0; i < list.size(); ++i) {
+ QWidget *next_widget = dynamic_cast(list.at(i));
+ if (!next_widget) continue;
+ QWidget* found=findQTextEditdisplaywidgets(next_widget,mode,objectName,recurseCount);
+ if (found) return found;
+ }
+ if (mode==debugDisplay && recurseCount==1) DEBUGF O("===================================================");
+ return nullptr;
+ }
+}
+#endif // TEST_ROUTIMES_ENABLED
+
+#endif // TEST_MACROS_ENABLED_ONCE