From b8e451771846eacab4b9bc9398437608fc98e1f4 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Thu, 6 Dec 2018 05:41:16 +0000 Subject: [PATCH] Improve performance of Fox and contest log view windows This include inverting the order of table view rows so the newest is at the top, without that the Qt MVC interactions when using a database table based model is too slow and complex to manage. The table views now have sort by column capability in the normal way (click column header to reverse sort order) for timely logging and non-disruption of Tx starts the log view should be sorted in descending time order and scrolled to the last row added. Without that Fox and contest logging will work but serious delays may be invoked that disrupt operation. --- item_delegates/CallsignDelegate.cpp | 1 + main.cpp | 9 +++++ models/CabrilloLog.cpp | 14 +++++-- models/FoxLog.cpp | 11 +++++- widgets/AbstractLogWindow.cpp | 59 ++++++++++++++++++----------- widgets/CabrilloLogWindow.cpp | 3 +- widgets/echoplot.cpp | 2 + widgets/echoplot.h | 11 ++++-- widgets/fastgraph.cpp | 1 + widgets/fastgraph.h | 6 ++- widgets/fastplot.cpp | 4 ++ widgets/fastplot.h | 13 ++++--- widgets/logqso.h | 4 +- widgets/mainwindow.cpp | 18 ++++++--- widgets/mainwindow.h | 14 ++++--- widgets/plotter.cpp | 6 +++ widgets/plotter.h | 12 ++---- widgets/widegraph.cpp | 2 + widgets/widegraph.h | 4 +- widgets/widgets.pri | 2 +- 20 files changed, 133 insertions(+), 63 deletions(-) diff --git a/item_delegates/CallsignDelegate.cpp b/item_delegates/CallsignDelegate.cpp index 017389458..d3b9864c1 100644 --- a/item_delegates/CallsignDelegate.cpp +++ b/item_delegates/CallsignDelegate.cpp @@ -28,3 +28,4 @@ void CallsignDelegate::setModelData (QWidget * editor, QAbstractItemModel * mode { model->setData (index, static_cast (editor)->text (), Qt::EditRole); } + diff --git a/main.cpp b/main.cpp index 601ae6a7e..fd510bffb 100644 --- a/main.cpp +++ b/main.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include #include @@ -21,6 +23,7 @@ #include #include #include +#include #include #include "revision_utils.hpp" @@ -288,6 +291,12 @@ int main(int argc, char *argv[]) throw std::runtime_error {("Database Error: " + db.lastError ().text ()).toStdString ()}; } + // better performance traded for a risk of d/b corruption + // on system crash or application crash + // db.exec ("PRAGMA synchronous=OFF"); // system crash risk + // db.exec ("PRAGMA journal_mode=MEMORY"); // application crash risk + db.exec ("PRAGMA locking_mode=EXCLUSIVE"); + int result; do { diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index d558e66e0..aaedd3bd1 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -59,6 +59,12 @@ CabrilloLog::impl::impl (Configuration const * configuration) setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent")); setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd")); setHeaderData (fieldIndex ("band"), Qt::Horizontal, tr ("Band")); + + // This descending order by time is important, it makes the view + // place the latest row at the top, without this the model/view + // interactions are both sluggish and unhelpful. + setSort (fieldIndex ("when"), Qt::DescendingOrder); + SQL_error_check (*this, &QSqlTableModel::select); } @@ -113,11 +119,11 @@ bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString c { m_->revert (); // discard any uncommitted changes } + m_->setEditStrategy (QSqlTableModel::OnManualSubmit); + ConditionalTransaction transaction {*m_}; auto ok = m_->insertRecord (-1, record); - if (ok) - { - m_->select (); // to refresh views - } + transaction.submit (); + m_->setEditStrategy (QSqlTableModel::OnFieldChange); return ok; } diff --git a/models/FoxLog.cpp b/models/FoxLog.cpp index 691647fdc..1f985f620 100644 --- a/models/FoxLog.cpp +++ b/models/FoxLog.cpp @@ -51,6 +51,12 @@ FoxLog::impl::impl () setHeaderData (fieldIndex ("report_sent"), Qt::Horizontal, tr ("Sent")); setHeaderData (fieldIndex ("report_rcvd"), Qt::Horizontal, tr ("Rcvd")); setHeaderData (fieldIndex ("band"), Qt::Horizontal, tr ("Band")); + + // This descending order by time is important, it makes the view + // place the latest row at the top, without this the model/view + // interactions are both sluggish and unhelpful. + setSort (fieldIndex ("when"), Qt::DescendingOrder); + SQL_error_check (*this, &QSqlTableModel::select); } @@ -104,11 +110,14 @@ bool FoxLog::add_QSO (QDateTime const& when, QString const& call, QString const& { m_->revert (); // discard any uncommitted changes } + m_->setEditStrategy (QSqlTableModel::OnManualSubmit); + ConditionalTransaction transaction {*m_}; auto ok = m_->insertRecord (-1, record); if (ok) { - m_->select (); // to refresh views + ok = transaction.submit (false); } + m_->setEditStrategy (QSqlTableModel::OnFieldChange); return ok; } diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp index c1bfd35c2..efa1e60f1 100644 --- a/widgets/AbstractLogWindow.cpp +++ b/widgets/AbstractLogWindow.cpp @@ -84,13 +84,23 @@ AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * s : QWidget {parent} , m_ {this, settings_key, settings, configuration} { - // ensure view scrolls to latest new row - connect (&m_->model_, &QAbstractItemModel::rowsInserted, this, [this] (QModelIndex const& parent, int /*first*/, int last) { - // note col 0 is hidden so use col 1 - // queued connection required otherwise row may not be available - // in time - if (m_->log_view_) m_->log_view_->scrollTo (m_->log_view_->model ()->index (last, 1, parent)); - }, Qt::QueuedConnection); + // this attempt to scroll to the last new record doesn't work, some + // sort of issue with model indexes and optimized DB fetches. For + // now sorting by the same column and direction as the underlying DB + // select and that DB select being in descending order so new rows + // at the end appear at view row 0 gets the job done + + // // ensure view scrolls to latest new row + // connect (&m_->model_, &QAbstractItemModel::rowsInserted, this, [this] (QModelIndex const& parent, int first, int last) { + // // note col 0 is hidden so use col 1 + // // queued connection required otherwise row may not be available + // // in time + // auto index = m_->model_.index (last, 1, parent); + // if (m_->log_view_) + // { + // m_->log_view_->scrollTo (index); + // } + // }, Qt::QueuedConnection); } AbstractLogWindow::~AbstractLogWindow () @@ -105,24 +115,27 @@ void AbstractLogWindow::set_log_view (QTableView * log_view) SettingsGroup g {m_->settings_, m_->settings_key_}; restoreGeometry (m_->settings_->value ("window/geometry").toByteArray ()); m_->log_view_ = log_view; - m_->log_view_->setContextMenuPolicy (Qt::ActionsContextMenu); - m_->log_view_->setAlternatingRowColors (true); - m_->log_view_->setSelectionBehavior (QAbstractItemView::SelectRows); - m_->log_view_->setSelectionMode (QAbstractItemView::ExtendedSelection); - m_->log_view_->setVerticalScrollMode (QAbstractItemView::ScrollPerPixel); - m_->model_.setSourceModel (m_->log_view_->model ()); - m_->log_view_->setModel (&m_->model_); - m_->log_view_->setColumnHidden (0, true); + set_log_view_font (m_->configuration_->decoded_text_font ()); + log_view->setSortingEnabled (true); + log_view->setContextMenuPolicy (Qt::ActionsContextMenu); + log_view->setAlternatingRowColors (true); + log_view->setSelectionBehavior (QAbstractItemView::SelectRows); + log_view->setSelectionMode (QAbstractItemView::ExtendedSelection); + log_view->setVerticalScrollMode (QAbstractItemView::ScrollPerPixel); + m_->model_.setSourceModel (log_view->model ()); + log_view->setModel (&m_->model_); + log_view->setColumnHidden (0, true); auto horizontal_header = log_view->horizontalHeader (); + horizontal_header->setResizeContentsPrecision (0); // visible region only horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); horizontal_header->setSectionsMovable (true); - m_->log_view_->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); - set_log_view_font (m_->configuration_->decoded_text_font ()); - m_->log_view_->scrollToBottom (); + auto vertical_header = log_view->horizontalHeader (); + vertical_header->setResizeContentsPrecision (0); // visible region only + vertical_header->setSectionResizeMode (QHeaderView::ResizeToContents); // actions - auto delete_action = new QAction {tr ("&Delete ..."), m_->log_view_}; - m_->log_view_->insertAction (nullptr, delete_action); + auto delete_action = new QAction {tr ("&Delete ..."), log_view}; + log_view->insertAction (nullptr, delete_action); connect (delete_action, &QAction::triggered, [this] (bool /*checked*/) { m_->delete_QSOs (); }); @@ -130,8 +143,8 @@ void AbstractLogWindow::set_log_view (QTableView * log_view) void AbstractLogWindow::set_log_view_font (QFont const& font) { - // m_->log_view_->setFont (font); - // m_->log_view_->horizontalHeader ()->setFont (font); - // m_->log_view_->verticalHeader ()->setFont (font); + m_->log_view_->setFont (font); + m_->log_view_->horizontalHeader ()->setFont (font); + m_->log_view_->verticalHeader ()->setFont (font); m_->model_.set_font (font); } diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index 4bf70f805..44a52cc6b 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -67,7 +67,8 @@ CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const m_->ui_.log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), 0, this}); - m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // band to first column + auto h_header = m_->ui_.log_table_view->horizontalHeader (); + h_header->moveSection (6, 1); // band to first column } CabrilloLogWindow::~CabrilloLogWindow () diff --git a/widgets/echoplot.cpp b/widgets/echoplot.cpp index 961173b06..0a93e889e 100644 --- a/widgets/echoplot.cpp +++ b/widgets/echoplot.cpp @@ -1,6 +1,8 @@ #include "echoplot.h" #include "commons.h" #include +#include +#include #include #include "moc_echoplot.cpp" diff --git a/widgets/echoplot.h b/widgets/echoplot.h index 23976b02e..a7492b974 100644 --- a/widgets/echoplot.h +++ b/widgets/echoplot.h @@ -4,17 +4,20 @@ // For more details see the accompanying file LICENSE_WHEATLEY.TXT /////////////////////////////////////////////////////////////////////////// -#ifndef EPLOTTER_H -#define EPLOTTER_H +#ifndef EPLOTTER_H_ +#define EPLOTTER_H_ -#include #include +#include #include -#include +#include #define VERT_DIVS 7 //specify grid screen divisions #define HORZ_DIVS 20 +class QPaintEvent; +class QResizeEvent; + class EPlotter : public QFrame { Q_OBJECT diff --git a/widgets/fastgraph.cpp b/widgets/fastgraph.cpp index 2c86d5dcb..e599138f2 100644 --- a/widgets/fastgraph.cpp +++ b/widgets/fastgraph.cpp @@ -3,6 +3,7 @@ #include "commons.h" #include #include +#include #include "fastplot.h" #include "SettingsGroup.hpp" diff --git a/widgets/fastgraph.h b/widgets/fastgraph.h index 1832d84c4..7ed32671f 100644 --- a/widgets/fastgraph.h +++ b/widgets/fastgraph.h @@ -1,5 +1,5 @@ -#ifndef FASTGRAPH_H -#define FASTGRAPH_H +#ifndef FASTGRAPH_H_ +#define FASTGRAPH_H_ #include #include @@ -9,6 +9,8 @@ namespace Ui { } class QSettings; +class QCloseEvent; +class QKeyEvent; class FastGraph : public QDialog { diff --git a/widgets/fastplot.cpp b/widgets/fastplot.cpp index cd186c2c8..1437834d8 100644 --- a/widgets/fastplot.cpp +++ b/widgets/fastplot.cpp @@ -1,6 +1,10 @@ #include "fastplot.h" #include "commons.h" #include +#include +#include +#include +#include #include #include "moc_fastplot.cpp" diff --git a/widgets/fastplot.h b/widgets/fastplot.h index 57a4ea904..b13913388 100644 --- a/widgets/fastplot.h +++ b/widgets/fastplot.h @@ -4,13 +4,16 @@ // For more details see the accompanying file LICENSE_WHEATLEY.TXT /////////////////////////////////////////////////////////////////////////// -#ifndef FPLOTTER_H -#define FPLOTTER_H +#ifndef FPLOTTER_H_ +#define FPLOTTER_H_ -#include #include -#include -#include +#include +#include +#include +#include + +class QMouseEvent; class FPlotter : public QFrame { diff --git a/widgets/logqso.h b/widgets/logqso.h index 346e3e5a2..3363d2eac 100644 --- a/widgets/logqso.h +++ b/widgets/logqso.h @@ -1,6 +1,6 @@ // -*- Mode: C++ -*- -#ifndef LogQSO_H -#define LogQSO_H +#ifndef LogQSO_H_ +#define LogQSO_H_ #include diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index d54b8f1c9..d7e883652 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -1,12 +1,20 @@ //---------------------------------------------------------- MainWindow #include "mainwindow.h" #include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -3100,7 +3108,7 @@ void MainWindow::readFromStdout() //readFromStdout if(w.at(0)==m_config.my_callsign() or w.at(0)==Radio::base_callsign(m_config.my_callsign())) { //### Check for ui->dxCallEntry->text()==foxCall before logging! ### ui->stopTxButton->click (); - on_logQSOButton_clicked(); + logQSOTimer.start(0); } if((w.at(2)==m_config.my_callsign() or w.at(2)==Radio::base_callsign(m_config.my_callsign())) and ui->tx3->text().length()>0) { @@ -3118,7 +3126,7 @@ void MainWindow::readFromStdout() //readFromStdout ui->tx3->text().length()>0) { if(w.at(2)=="RR73") { ui->stopTxButton->click (); - on_logQSOButton_clicked(); + logQSOTimer.start(0); } else { if(w.at(1)==Radio::base_callsign(ui->dxCallEntry->text()) and (w.at(2).mid(0,1)=="+" or w.at(2).mid(0,1)=="-")) { @@ -4453,7 +4461,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie m_nextCall=""; //### Temporary: disable use of "TU;" message if(SpecOp::RTTY == m_config.special_op_id() and m_nextCall!="") { // We're in RTTY contest and have "nextCall" queued up: send a "TU; ..." message - on_logQSOButton_clicked(); + logQSOTimer.start(0); ui->tx3->setText(ui->tx3->text().remove("TU; ")); useNextCall(); QString t="TU; " + ui->tx3->text(); @@ -4462,7 +4470,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } else { // if(SpecOp::RTTY == m_config.special_op_id()) { if(false) { - on_logQSOButton_clicked(); + logQSOTimer.start(0); m_ntx=6; ui->txrb6->setChecked(true); } else { @@ -8216,7 +8224,7 @@ list2Done: { writeFoxQSO (QString {" Log: %1 %2 %3 %4 %5"}.arg (m_hisCall).arg (m_hisGrid) .arg (m_rptSent).arg (m_rptRcvd).arg (m_lastBand)); - on_logQSOButton_clicked(); + logQSOTimer.start(0); m_foxRateQueue.enqueue (now); //Add present time in seconds //to Rate queue. } diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 428ea6890..cfae42029 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -1,12 +1,12 @@ // -*- Mode: C++ -*- #ifndef MAINWINDOW_H #define MAINWINDOW_H -#ifdef QT5 -#include -#else -#include -#endif + +#include +#include #include +#include +#include #include #include #include @@ -58,6 +58,8 @@ namespace Ui { class MainWindow; } +class QSharedMemory; +class QSplashScreen; class QSettings; class QLineEdit; class QFont; @@ -102,6 +104,8 @@ public: QWidget *parent = nullptr); ~MainWindow(); + int decoderBusy () const {return m_decoderBusy;} + public slots: void showSoundInError(const QString& errorMsg); void showSoundOutError(const QString& errorMsg); diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index cf3166127..761dae08d 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -1,5 +1,11 @@ #include "plotter.h" #include +#include +#include +#include +#include +#include +#include #include #include "commons.h" #include "moc_plotter.cpp" diff --git a/widgets/plotter.h b/widgets/plotter.h index 20d1739ac..e243c1777 100644 --- a/widgets/plotter.h +++ b/widgets/plotter.h @@ -5,18 +5,14 @@ // For more details see the accompanying file LICENSE_WHEATLEY.TXT /////////////////////////////////////////////////////////////////////////// -#ifndef PLOTTER_H -#define PLOTTER_H +#ifndef PLOTTER_H_ +#define PLOTTER_H_ -#ifdef QT5 -#include -#else -#include -#endif #include +#include #include #include -#include +#include #define VERT_DIVS 7 //specify grid screen divisions #define HORZ_DIVS 20 diff --git a/widgets/widegraph.cpp b/widgets/widegraph.cpp index 350eae9b0..b4601ba4c 100644 --- a/widgets/widegraph.cpp +++ b/widgets/widegraph.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "ui_widegraph.h" #include "commons.h" #include "Configuration.hpp" diff --git a/widgets/widegraph.h b/widgets/widegraph.h index f5e57f8dc..a809a6c8c 100644 --- a/widgets/widegraph.h +++ b/widgets/widegraph.h @@ -1,6 +1,6 @@ // -*- Mode: C++ -*- -#ifndef WIDEGRAPH_H -#define WIDEGRAPH_H +#ifndef WIDEGRAPH_H_ +#define WIDEGRAPH_H_ #include #include diff --git a/widgets/widgets.pri b/widgets/widgets.pri index e70c5cb9e..24ddd5a3c 100644 --- a/widgets/widgets.pri +++ b/widgets/widgets.pri @@ -19,7 +19,7 @@ HEADERS += \ widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \ widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \ widgets/ExportCabrillo.h widgets/AbstractLogWindow.hpp \ - widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp + widgets/FoxLogWindow.hpp widgets/CabrilloLogWindow.hpp FORMS += \ widgets/mainwindow.ui widgets/about.ui \