From 127a3e1964889bece5e42071c0b5fe1ca97f4949 Mon Sep 17 00:00:00 2001 From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com> Date: Sat, 18 Jan 2020 11:41:09 -0500 Subject: [PATCH 1/4] Fix logger thread so that it doesn't lose messages at startup. This was particularly noticeable when running for the first time and selecting OSCAR's data location. --- oscar/logger.cpp | 20 ++++++++++++++++++-- oscar/logger.h | 6 ++++-- oscar/main.cpp | 2 +- oscar/mainwindow.cpp | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/oscar/logger.cpp b/oscar/logger.cpp index 8bfc1731..b57152ce 100644 --- a/oscar/logger.cpp +++ b/oscar/logger.cpp @@ -1,5 +1,6 @@ -/* OSCAR Logger module implementation +/* OSCAR Logger module implementation * + * Copyright (c) 2020 The OSCAR Team * Copyright (c) 2011-2018 Mark Watkins * * This file is subject to the terms and conditions of the GNU General Public @@ -59,18 +60,32 @@ void MyOutputHandler(QtMsgType type, const QMessageLogContext &context, const QS } +static QMutex s_LoggerRunning; + void initializeLogger() { + s_LoggerRunning.lock(); // lock until the thread starts running logger = new LogThread(); otherThreadPool = new QThreadPool(); bool b = otherThreadPool->tryStart(logger); + if (b) { + s_LoggerRunning.lock(); // wait until the thread begins running + s_LoggerRunning.unlock(); // we no longer need the lock + } qInstallMessageHandler(MyOutputHandler); if (b) { qDebug() << "Started logging thread"; } else { qWarning() << "Logging thread did not start correctly"; } +} +void LogThread::connectionReady() +{ + strlock.lock(); + connected = true; + strlock.unlock(); + qDebug() << "Logging UI initialized"; } void shutdownLogger() @@ -117,10 +132,11 @@ void LogThread::quit() { void LogThread::run() { running = true; + s_LoggerRunning.unlock(); // unlock as soon as the thread begins to run do { strlock.lock(); //int r = receivers(SIGNAL(outputLog(QString()))); - while (!buffer.isEmpty()) { + while (connected && !buffer.isEmpty()) { QString msg = buffer.takeFirst(); fprintf(stderr, "%s\n", msg.toLocal8Bit().data()); emit outputLog(msg); diff --git a/oscar/logger.h b/oscar/logger.h index 20cbd609..6868c25c 100644 --- a/oscar/logger.h +++ b/oscar/logger.h @@ -1,4 +1,4 @@ -#ifndef LOGGER_H +#ifndef LOGGER_H #define LOGGER_H #include @@ -16,13 +16,14 @@ class LogThread:public QObject, public QRunnable { Q_OBJECT public: - explicit LogThread() : QRunnable() { running = false; logtime.start(); } + explicit LogThread() : QRunnable() { running = false; logtime.start(); connected = false; } virtual ~LogThread() {} void run(); void append(QString msg); void appendClean(QString msg); bool isRunning() { return running; } + void connectionReady(); void quit(); @@ -34,6 +35,7 @@ signals: protected: volatile bool running; QTime logtime; + bool connected; }; extern LogThread * logger; diff --git a/oscar/main.cpp b/oscar/main.cpp index 57a1d7ec..53ec0756 100644 --- a/oscar/main.cpp +++ b/oscar/main.cpp @@ -1,5 +1,6 @@ /* OSCAR Main * + * Copyright (c) 2019-2020 The OSCAR Team * Copyright (c) 2011-2018 Mark Watkins * * This file is subject to the terms and conditions of the GNU General Public @@ -338,7 +339,6 @@ int main(int argc, char *argv[]) { } initializeLogger(); - QThread::msleep(50); // Logger takes a little bit to catch up qDebug().noquote() << "OSCAR starting" << QDateTime::currentDateTime().toString(); diff --git a/oscar/mainwindow.cpp b/oscar/mainwindow.cpp index db1c7f94..11b52e8b 100644 --- a/oscar/mainwindow.cpp +++ b/oscar/mainwindow.cpp @@ -69,10 +69,10 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow) { ui->setupUi(this); - ui->logText->setPlainText("00000: Startup: OSCAR Logger initialized"); if (logger) { connect(logger, SIGNAL(outputLog(QString)), this, SLOT(logMessage(QString))); + logger->connectionReady(); } // Bring window to top (useful when language is changed) From 91dbd3a20428be53e5b7b28e01fc91431e3ccc9f Mon Sep 17 00:00:00 2001 From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com> Date: Sat, 18 Jan 2020 17:01:35 -0500 Subject: [PATCH 2/4] Fix the display of Preferences menu shortcut on macOS. It was appearing only on first launch, when OSCAR was asking where to store its data. Now it appears consistently. --- oscar/mainwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/oscar/mainwindow.cpp b/oscar/mainwindow.cpp index 11b52e8b..f7187a17 100644 --- a/oscar/mainwindow.cpp +++ b/oscar/mainwindow.cpp @@ -130,6 +130,12 @@ void MainWindow::SetupGUI() #ifdef Q_OS_MAC ui->action_About->setMenuRole(QAction::ApplicationSpecificRole); ui->action_Preferences->setMenuRole(QAction::ApplicationSpecificRole); + + // For some reason, setShortcuts won't change the text of the menu item unless Qt has had a chance + // to do something first. Without the processEvents() call it still installs the shortcut, but + // not visible. (Any preceding UI such as QMessageBox seems to have the same effect.) + QApplication::processEvents(); + ui->action_Preferences->setShortcuts(QKeySequence::Preferences); #endif From d8cc14250181b003a076ee6e4ced016ffbe1101c Mon Sep 17 00:00:00 2001 From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com> Date: Sat, 18 Jan 2020 20:16:31 -0500 Subject: [PATCH 3/4] Add "ignore older than" support to PRS1 importer. Now it actually works. --- oscar/SleepLib/loader_plugins/prs1_loader.cpp | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp index cde3fe86..f0daf26e 100644 --- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp +++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp @@ -891,10 +891,9 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin QDateTime datetime; - /* Unused until we get an actual timestamp below. - QDateTime ignoreBefore = p_profile->session->ignoreOlderSessionsDate(); + qint64 ignoreBefore = p_profile->session->ignoreOlderSessionsDate().toSecsSinceEpoch(); bool ignoreOldSessions = p_profile->session->ignoreOlderSessions(); - */ + QSet skipped; // for each p0/p1/p2/etc... folder for (int p=0; p < size; ++p) { @@ -937,15 +936,6 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin continue; } - /* This never worked: the filename isn't a timestamp. - if (ignoreOldSessions) { - datetime = QDateTime::fromTime_t(sid); - if (datetime < ignoreBefore) { - continue; - } - } - */ - // TODO: BUG: This isn't right, since files can have multiple session // chunks, which might not correspond to the filename. But before we can // fix this we need to come up with a reasonably fast way to filter previously @@ -957,6 +947,16 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin } if ((ext == 5) || (ext == 6)) { + if (skipped.contains(sid)) { + // We don't know the timestamp until the file is parsed, which we only do for + // waveform data at import (after scanning) since it's so large. If we relied + // solely on the chunks' timestamps at that point, we'd get half of an otherwise + // skipped session (the half after midnight). + // + // So we skip the entire file here based on the session's other data. + continue; + } + // Waveform files aren't grouped... so we just want to add the filename for later QHash::iterator it = sesstasks.find(sid); if (it != sesstasks.end()) { @@ -1013,7 +1013,14 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin delete chunk; continue; } - + if (ignoreOldSessions && chunk->timestamp < ignoreBefore) { + qDebug().noquote() << relativePath(path) << "skipping session" << chunk_sid << ":" + << QDateTime::fromSecsSinceEpoch(chunk->timestamp).toString() << "older than" + << QDateTime::fromSecsSinceEpoch(ignoreBefore).toString(); + skipped += chunk_sid; + delete chunk; + continue; + } task = nullptr; QHash::iterator it = sesstasks.find(chunk_sid); @@ -7670,7 +7677,26 @@ QList PRS1Import::CoalesceWaveformChunks(QList lastchunk = chunk; } - return coalesced; + // In theory there could be broken sessions that have waveform data but no summary or events. + // Those waveforms won't be skipped by the scanner, so we have to check for them here. + // + // This won't be perfect, since any coalesced chunks starting after midnight of the threshhold + // date will also be imported, but those should be relatively few, and tolerable imprecision. + QList coalescedAndFiltered; + qint64 ignoreBefore = p_profile->session->ignoreOlderSessionsDate().toSecsSinceEpoch(); + bool ignoreOldSessions = p_profile->session->ignoreOlderSessions(); + + for (auto & chunk : coalesced) { + if (ignoreOldSessions && chunk->timestamp < ignoreBefore) { + qWarning().noquote() << relativePath(chunk->m_path) << "skipping session" << chunk->sessionid << ":" + << QDateTime::fromSecsSinceEpoch(chunk->timestamp).toString() << "older than" + << QDateTime::fromSecsSinceEpoch(ignoreBefore).toString(); + continue; + } + coalescedAndFiltered.append(chunk); + } + + return coalescedAndFiltered; } From aba58d90851816974610b02fe95a6e4e1bd6472a Mon Sep 17 00:00:00 2001 From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com> Date: Sat, 18 Jan 2020 20:34:10 -0500 Subject: [PATCH 4/4] Second pass at fixing display of Preferences menu shortcut on macOS. The previous fix didn't work 100% of the time either. --- oscar/mainwindow.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/oscar/mainwindow.cpp b/oscar/mainwindow.cpp index f7187a17..d356c44e 100644 --- a/oscar/mainwindow.cpp +++ b/oscar/mainwindow.cpp @@ -128,15 +128,8 @@ void MainWindow::SetupGUI() setWindowTitle(getMainWindowTitle()); #ifdef Q_OS_MAC - ui->action_About->setMenuRole(QAction::ApplicationSpecificRole); - ui->action_Preferences->setMenuRole(QAction::ApplicationSpecificRole); - - // For some reason, setShortcuts won't change the text of the menu item unless Qt has had a chance - // to do something first. Without the processEvents() call it still installs the shortcut, but - // not visible. (Any preceding UI such as QMessageBox seems to have the same effect.) - QApplication::processEvents(); - - ui->action_Preferences->setShortcuts(QKeySequence::Preferences); + ui->action_About->setMenuRole(QAction::AboutRole); + ui->action_Preferences->setMenuRole(QAction::PreferencesRole); #endif ui->actionLine_Cursor->setChecked(AppSetting->lineCursorMode());