From a43e6a93e43d4cda1cfa735c6aec960b8c56c7ec Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Fri, 4 Oct 2019 18:40:22 +0200 Subject: [PATCH] Store settings in SqliteTableModel Store the relevant settings in SqliteTableModel and only update them when they have changed. This avoids a lot of querying and converting of variables in the data() function which is called very often and therefore is somewhat critical for the overall performance. --- src/ExtendedTableWidget.cpp | 2 +- src/SqlExecutionArea.cpp | 6 ++--- src/TableBrowser.cpp | 4 +-- src/sqlitetablemodel.cpp | 49 +++++++++++++++++++++++-------------- src/sqlitetablemodel.h | 39 +++++++++++++++++++++-------- 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/ExtendedTableWidget.cpp b/src/ExtendedTableWidget.cpp index 611c6b86..cb0179dc 100644 --- a/src/ExtendedTableWidget.cpp +++ b/src/ExtendedTableWidget.cpp @@ -150,7 +150,7 @@ QWidget* ExtendedTableWidgetEditorDelegate::createEditor(QWidget* parent, const if (!currentTable->fields.at(static_cast(index.column())-1).notnull()) query.append (" UNION SELECT NULL"); - SqliteTableModel* fkModel = new SqliteTableModel(m->db(), parent, m->chunkSize(), m->encoding()); + SqliteTableModel* fkModel = new SqliteTableModel(m->db(), parent, m->encoding()); fkModel->setQuery(query); QComboBox* combo = new QComboBox(parent); diff --git a/src/SqlExecutionArea.cpp b/src/SqlExecutionArea.cpp index cf59ff6e..352bfabf 100644 --- a/src/SqlExecutionArea.cpp +++ b/src/SqlExecutionArea.cpp @@ -22,7 +22,7 @@ SqlExecutionArea::SqlExecutionArea(DBBrowserDB& _db, QWidget* parent) : ui->setupUi(this); // Create model - model = new SqliteTableModel(db, this, static_cast(Settings::getValue("db", "prefetchsize").toUInt())); + model = new SqliteTableModel(db, this); ui->tableResult->setModel(model); connect(model, &SqliteTableModel::finishedFetch, this, &SqlExecutionArea::fetchedData); @@ -149,8 +149,8 @@ void SqlExecutionArea::reloadSettings() ui->splitter->restoreState(Settings::getValue("editor", "splitter1_sizes").toByteArray()); ui->splitter_2->restoreState(Settings::getValue("editor", "splitter2_sizes").toByteArray()); - // Set prefetch settings - model->setChunkSize(static_cast(Settings::getValue("db", "prefetchsize").toUInt())); + // Reload model settings + model->reloadSettings(); // Check if error indicators are enabled for the not-ok background clue showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool(); diff --git a/src/TableBrowser.cpp b/src/TableBrowser.cpp index ca230362..cf90499d 100644 --- a/src/TableBrowser.cpp +++ b/src/TableBrowser.cpp @@ -287,7 +287,7 @@ void TableBrowser::init(DBBrowserDB* _db) if(m_model) delete m_model; - m_model = new SqliteTableModel(*db, this, static_cast(Settings::getValue("db", "prefetchsize").toUInt())); + m_model = new SqliteTableModel(*db, this); connect(m_model, &SqliteTableModel::finishedFetch, this, &TableBrowser::updateRecordsetLabel); } @@ -537,7 +537,7 @@ void TableBrowser::reloadSettings() ui->dataTable->reloadSettings(); ui->browseToolbar->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleBrowse").toInt())); - m_model->setChunkSize(static_cast(Settings::getValue("db", "prefetchsize").toUInt())); + m_model->reloadSettings(); } void TableBrowser::setCurrentTable(const sqlb::ObjectIdentifier& name) diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index 5ef170eb..c2aefe7f 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -20,14 +20,16 @@ using json = nlohmann::json; -SqliteTableModel::SqliteTableModel(DBBrowserDB& db, QObject* parent, size_t chunkSize, const QString& encoding) +SqliteTableModel::SqliteTableModel(DBBrowserDB& db, QObject* parent, const QString& encoding) : QAbstractTableModel(parent) , m_db(db) , m_lifeCounter(0) , m_currentRowCount(0) - , m_chunkSize(chunkSize) , m_encoding(encoding) { + // Load initial settings first + reloadSettings(); + worker = new RowLoader( [this](){ return m_db.get(tr("reading rows")); }, [this](QString stmt){ return m_db.logSQL(stmt, kLogMsg_App); }, @@ -114,11 +116,6 @@ void SqliteTableModel::reset() endResetModel(); } -void SqliteTableModel::setChunkSize(size_t chunksize) -{ - m_chunkSize = chunksize; -} - void SqliteTableModel::setQuery(const sqlb::Query& query) { // Unset all previous settings. When setting a table all information on the previously browsed data set is removed first. @@ -341,15 +338,14 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const return tr("loading..."); if(role == Qt::DisplayRole && cached_row->at(column).isNull()) { - return Settings::getValue("databrowser", "null_text").toString(); + return m_nullText; } else if(role == Qt::DisplayRole && nosync_isBinary(index)) { - return Settings::getValue("databrowser", "blob_text").toString(); + return m_blobText; } else if(role == Qt::DisplayRole) { - int limit = Settings::getValue("databrowser", "symbol_limit").toInt(); QByteArray displayText = cached_row->at(column); - if (displayText.length() > limit) { + if (displayText.length() > m_symbolLimit) { // Add "..." to the end of truncated strings - return decode(displayText.left(limit).append(" ...")); + return decode(displayText.left(m_symbolLimit).append(" ...")); } else { return decode(displayText); } @@ -373,9 +369,9 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const if(!row_available) return QColor(100, 100, 100); if(cached_row->at(column).isNull()) - return QColor(Settings::getValue("databrowser", "null_fg_colour").toString()); + return m_nullFgColour; else if (nosync_isBinary(index)) - return QColor(Settings::getValue("databrowser", "bin_fg_colour").toString()); + return m_binFgColour; else if (m_mCondFormats.find(column) != m_mCondFormats.end()) { QString value = cached_row->at(column); // Unlock before querying from DB @@ -385,14 +381,14 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const return condFormatColor; } // Regular case (not null, not binary and no matching conditional format) - return QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()); + return m_regFgColour; } else if (role == Qt::BackgroundRole) { if(!row_available) return QColor(255, 200, 200); if(cached_row->at(column).isNull()) - return QColor(Settings::getValue("databrowser", "null_bg_colour").toString()); + return m_nullBgColour; else if (nosync_isBinary(index)) - return QColor(Settings::getValue("databrowser", "bin_bg_colour").toString()); + return m_binBgColour; else if (m_mCondFormats.find(column) != m_mCondFormats.end()) { QString value = cached_row->at(column); // Unlock before querying from DB @@ -402,7 +398,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const return condFormatColor; } // Regular case (not null, not binary and no matching conditional format) - return QColor(Settings::getValue("databrowser", "reg_bg_colour").toString()); + return m_regBgColour; } else if(role == Qt::ToolTipRole) { sqlb::ForeignKeyClause fk = getForeignKeyClause(column-1); if(fk.isSet()) @@ -427,7 +423,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const if(!row_available) return QVariant(); - if(Settings::getValue("databrowser", "image_preview").toBool() && !isImageData(cached_row->at(column)).isNull()) + if(m_imagePreviewEnabled && !isImageData(cached_row->at(column)).isNull()) { QImage img; img.loadFromData(cached_row->at(column)); @@ -1151,3 +1147,18 @@ QModelIndex SqliteTableModel::nextMatch(const QModelIndex& start, const std::vec return pos; } } + +void SqliteTableModel::reloadSettings() +{ + m_nullText = Settings::getValue("databrowser", "null_text").toString(); + m_blobText = Settings::getValue("databrowser", "blob_text").toString(); + m_regFgColour = QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()); + m_regBgColour = QColor(Settings::getValue("databrowser", "reg_bg_colour").toString()); + m_nullFgColour = QColor(Settings::getValue("databrowser", "null_fg_colour").toString()); + m_nullBgColour = QColor(Settings::getValue("databrowser", "null_bg_colour").toString()); + m_binFgColour = QColor(Settings::getValue("databrowser", "bin_fg_colour").toString()); + m_binBgColour = QColor(Settings::getValue("databrowser", "bin_bg_colour").toString()); + m_symbolLimit = Settings::getValue("databrowser", "symbol_limit").toInt(); + m_imagePreviewEnabled = Settings::getValue("databrowser", "image_preview").toBool(); + m_chunkSize = static_cast(Settings::getValue("db", "prefetchsize").toUInt()); +} diff --git a/src/sqlitetablemodel.h b/src/sqlitetablemodel.h index 2c173b46..8162ad73 100644 --- a/src/sqlitetablemodel.h +++ b/src/sqlitetablemodel.h @@ -2,6 +2,7 @@ #define SQLITETABLEMODEL_H #include +#include #include #include @@ -25,7 +26,7 @@ class SqliteTableModel : public QAbstractTableModel #endif public: - explicit SqliteTableModel(DBBrowserDB& db, QObject *parent = nullptr, size_t chunkSize = 50000, const QString& encoding = QString()); + explicit SqliteTableModel(DBBrowserDB& db, QObject *parent = nullptr, const QString& encoding = QString()); ~SqliteTableModel() override; /// reset to state after construction @@ -86,8 +87,6 @@ public: /// configure for browsing specified table void setQuery(const sqlb::Query& query); - void setChunkSize(size_t chunksize); - size_t chunkSize() { return m_chunkSize; } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void sort(const std::vector& columns); sqlb::ObjectIdentifier currentTableName() const { return m_query.table(); } @@ -132,6 +131,8 @@ public: DBBrowserDB& db() { return m_db; } + void reloadSettings(); + public slots: void updateFilter(size_t column, const QString& value); void updateGlobalFilter(const std::vector& values); @@ -200,6 +201,31 @@ private: std::map> m_mCondFormats; sqlb::Query m_query; + QString m_encoding; + + /** + * These are used for multi-threaded population of the table + */ + mutable QMutex m_mutexDataCache; + +private: + /** + * Settings. These are stored here to avoid fetching and converting them every time we need them. Because this class + * uses a lot of settings and because some of its functions are called very often, this should speed things up noticeable. + * Call reloadSettings() to update these. + */ + + QString m_nullText; + QString m_blobText; + QColor m_regFgColour; + QColor m_regBgColour; + QColor m_nullFgColour; + QColor m_nullBgColour; + QColor m_binFgColour; + QColor m_binBgColour; + int m_symbolLimit; + bool m_imagePreviewEnabled; + /** * @brief m_chunkSize Size of the next chunk fetch more will try to fetch. * This value should be rather high, because our query @@ -209,13 +235,6 @@ private: * to that row count. */ size_t m_chunkSize; - - QString m_encoding; - - /** - * These are used for multi-threaded population of the table - */ - mutable QMutex m_mutexDataCache; }; #endif