mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-17 01:09:36 -06:00
Speed up the loading of the database structure
While testing the original database from issue #1892 which contains hundreds of tables and fields, I noticed how long the loading of the database structure takes. This is especially problematic since it needs to be reloaded on various occasions, e.g. running most statements in the Execute SQL tab, which stalls the application every time. According to a profiler it is the QIcon constructor which requires most of the time. By introducing this small icon cache class we can reduce the time for loading icons to almost nothing. While still not perfect the UI already feels much more responsive with this patch.
This commit is contained in:
@@ -127,6 +127,7 @@ set(SQLB_HDR
|
||||
src/grammar/Sqlite3Lexer.hpp
|
||||
src/grammar/Sqlite3Parser.hpp
|
||||
src/Data.h
|
||||
src/IconCache.h
|
||||
)
|
||||
|
||||
set(SQLB_MOC_HDR
|
||||
@@ -228,6 +229,7 @@ set(SQLB_SRC
|
||||
src/CondFormat.cpp
|
||||
src/RunSql.cpp
|
||||
src/ProxyDialog.cpp
|
||||
src/IconCache.cpp
|
||||
)
|
||||
|
||||
set(SQLB_FORMS
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "DbStructureModel.h"
|
||||
#include <IconCache.h>
|
||||
#include "sqlitedb.h"
|
||||
#include "sqlitetablemodel.h"
|
||||
#include "Settings.h"
|
||||
@@ -160,12 +161,12 @@ void DbStructureModel::reloadData()
|
||||
// The second node contains four sub-nodes (tables, indices, views and triggers), each containing a list of objects of that type.
|
||||
// This way we only have to have and only have to update one model and can use it in all sorts of places, just by setting a different root node.
|
||||
browsablesRootItem = new QTreeWidgetItem(rootItem);
|
||||
browsablesRootItem->setIcon(ColumnName, QIcon(QString(":/icons/view")));
|
||||
browsablesRootItem->setIcon(ColumnName, IconCache::get("view"));
|
||||
browsablesRootItem->setText(ColumnName, tr("Browsables"));
|
||||
|
||||
// Make sure to always load the main schema first
|
||||
QTreeWidgetItem* itemAll = new QTreeWidgetItem(rootItem);
|
||||
itemAll->setIcon(ColumnName, QIcon(QString(":/icons/database")));
|
||||
itemAll->setIcon(ColumnName, IconCache::get("database"));
|
||||
itemAll->setText(ColumnName, tr("All"));
|
||||
itemAll->setText(ColumnObjectType, "database");
|
||||
buildTree(itemAll, "main");
|
||||
@@ -174,7 +175,7 @@ void DbStructureModel::reloadData()
|
||||
if(!m_db.schemata["temp"].empty())
|
||||
{
|
||||
QTreeWidgetItem* itemTemp = new QTreeWidgetItem(itemAll);
|
||||
itemTemp->setIcon(ColumnName, QIcon(QString(":/icons/database")));
|
||||
itemTemp->setIcon(ColumnName, IconCache::get("database"));
|
||||
itemTemp->setText(ColumnName, tr("Temporary"));
|
||||
itemTemp->setText(ColumnObjectType, "database");
|
||||
buildTree(itemTemp, "temp");
|
||||
@@ -187,7 +188,7 @@ void DbStructureModel::reloadData()
|
||||
if(it.first != "main" && it.first != "temp")
|
||||
{
|
||||
QTreeWidgetItem* itemSchema = new QTreeWidgetItem(itemAll);
|
||||
itemSchema->setIcon(ColumnName, QIcon(QString(":/icons/database")));
|
||||
itemSchema->setIcon(ColumnName, IconCache::get("database"));
|
||||
itemSchema->setText(ColumnName, QString::fromStdString(it.first));
|
||||
itemSchema->setText(ColumnObjectType, "database");
|
||||
buildTree(itemSchema, it.first);
|
||||
@@ -321,22 +322,22 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const std::string& sch
|
||||
|
||||
// Prepare tree
|
||||
QTreeWidgetItem* itemTables = new QTreeWidgetItem(parent);
|
||||
itemTables->setIcon(ColumnName, QIcon(QString(":/icons/table")));
|
||||
itemTables->setIcon(ColumnName, IconCache::get("table"));
|
||||
itemTables->setText(ColumnName, tr("Tables (%1)").arg(calc_number_of_objects_by_type(objmap, "table")));
|
||||
typeToParentItem.insert({"table", itemTables});
|
||||
|
||||
QTreeWidgetItem* itemIndices = new QTreeWidgetItem(parent);
|
||||
itemIndices->setIcon(ColumnName, QIcon(QString(":/icons/index")));
|
||||
itemIndices->setIcon(ColumnName, IconCache::get("index"));
|
||||
itemIndices->setText(ColumnName, tr("Indices (%1)").arg(calc_number_of_objects_by_type(objmap, "index")));
|
||||
typeToParentItem.insert({"index", itemIndices});
|
||||
|
||||
QTreeWidgetItem* itemViews = new QTreeWidgetItem(parent);
|
||||
itemViews->setIcon(ColumnName, QIcon(QString(":/icons/view")));
|
||||
itemViews->setIcon(ColumnName, IconCache::get("view"));
|
||||
itemViews->setText(ColumnName, tr("Views (%1)").arg(calc_number_of_objects_by_type(objmap, "view")));
|
||||
typeToParentItem.insert({"view", itemViews});
|
||||
|
||||
QTreeWidgetItem* itemTriggers = new QTreeWidgetItem(parent);
|
||||
itemTriggers->setIcon(ColumnName, QIcon(QString(":/icons/trigger")));
|
||||
itemTriggers->setIcon(ColumnName, IconCache::get("trigger"));
|
||||
itemTriggers->setText(ColumnName, tr("Triggers (%1)").arg(calc_number_of_objects_by_type(objmap, "trigger")));
|
||||
typeToParentItem.insert({"trigger", itemTriggers});
|
||||
|
||||
@@ -377,11 +378,11 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const std::string& sch
|
||||
fldItem->setText(ColumnSQL, QString::fromStdString(field.sql));
|
||||
fldItem->setText(ColumnSchema, QString::fromStdString(schema));
|
||||
if(contains(pk_columns, field.name))
|
||||
fldItem->setIcon(ColumnName, QIcon(":/icons/field_key"));
|
||||
fldItem->setIcon(ColumnName, IconCache::get("field_key"));
|
||||
else if(isFK)
|
||||
fldItem->setIcon(ColumnName, QIcon(":/icons/field_fk"));
|
||||
fldItem->setIcon(ColumnName, IconCache::get("field_fk"));
|
||||
else
|
||||
fldItem->setIcon(ColumnName, QIcon(":/icons/field"));
|
||||
fldItem->setIcon(ColumnName, IconCache::get("field"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,12 +390,12 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const std::string& sch
|
||||
|
||||
QTreeWidgetItem* DbStructureModel::addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const std::string& schema)
|
||||
{
|
||||
QString type = QString::fromStdString(sqlb::Object::typeToString(object->type()));
|
||||
std::string type = sqlb::Object::typeToString(object->type());
|
||||
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(parent);
|
||||
item->setIcon(ColumnName, QIcon(QString(":/icons/%1").arg(type)));
|
||||
item->setIcon(ColumnName, IconCache::get(type));
|
||||
item->setText(ColumnName, QString::fromStdString(object->name()));
|
||||
item->setText(ColumnObjectType, type);
|
||||
item->setText(ColumnObjectType, QString::fromStdString(type));
|
||||
item->setText(ColumnSQL, QString::fromStdString(object->originalSql()));
|
||||
item->setText(ColumnSchema, QString::fromStdString(schema));
|
||||
|
||||
|
||||
22
src/IconCache.cpp
Normal file
22
src/IconCache.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "IconCache.h"
|
||||
|
||||
QIcon IconCache::null_icon;
|
||||
std::unordered_map<std::string, QIcon> IconCache::icons;
|
||||
|
||||
const QIcon& IconCache::get(const std::string& name)
|
||||
{
|
||||
// Check if we already have an icon object with that name in the cache. If so, just return that
|
||||
auto it = icons.find(name);
|
||||
if(it != icons.end())
|
||||
return it->second;
|
||||
|
||||
// If now, try to load an icon with that name and insert it into the cache
|
||||
QIcon icon(":/icons/" + QString::fromStdString(name));
|
||||
auto ins = icons.insert({name, icon});
|
||||
|
||||
// If the insertion was successful, return the inserted icon object. If it was not, return a null icon.
|
||||
if(ins.second)
|
||||
return ins.first->second;
|
||||
else
|
||||
return null_icon;
|
||||
}
|
||||
21
src/IconCache.h
Normal file
21
src/IconCache.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef ICONCACHE_H
|
||||
#define ICONCACHE_H
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class IconCache
|
||||
{
|
||||
public:
|
||||
IconCache() = delete;
|
||||
|
||||
static const QIcon& get(const std::string& name);
|
||||
|
||||
private:
|
||||
static QIcon null_icon;
|
||||
static std::unordered_map<std::string, QIcon> icons;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -75,7 +75,8 @@ HEADERS += \
|
||||
sql/Query.h \
|
||||
RunSql.h \
|
||||
sql/ObjectIdentifier.h \
|
||||
ProxyDialog.h
|
||||
ProxyDialog.h \
|
||||
IconCache.h
|
||||
|
||||
SOURCES += \
|
||||
sqlitedb.cpp \
|
||||
@@ -127,7 +128,8 @@ SOURCES += \
|
||||
sql/Query.cpp \
|
||||
RunSql.cpp \
|
||||
sql/ObjectIdentifier.cpp \
|
||||
ProxyDialog.cpp
|
||||
ProxyDialog.cpp \
|
||||
IconCache.cpp
|
||||
|
||||
RESOURCES += icons/icons.qrc \
|
||||
translations/flags/flags.qrc \
|
||||
|
||||
Reference in New Issue
Block a user