diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index f6cd0cea20..2b1e514208 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -286,6 +286,20 @@ void MainWindow::init() #endif // Set statusbar fields + statusBusyLabel = new QLabel(ui->statusbar); + statusBusyLabel->setEnabled(false); + statusBusyLabel->setVisible(false); + statusBusyLabel->setToolTip(tr("The database is currenctly busy.")); + ui->statusbar->addPermanentWidget(statusBusyLabel); + + statusStopButton = new QToolButton(ui->statusbar); + statusStopButton->setVisible(false); + statusStopButton->setIcon(QIcon(":icons/cancel")); + statusStopButton->setToolTip(tr("Click here to interrupt the currently running query.")); + statusStopButton->setMaximumSize(ui->statusbar->geometry().height() - 6, ui->statusbar->geometry().height() - 6); + statusStopButton->setAutoRaise(true); + ui->statusbar->addPermanentWidget(statusStopButton); + statusEncryptionLabel = new QLabel(ui->statusbar); statusEncryptionLabel->setEnabled(false); statusEncryptionLabel->setVisible(false); @@ -316,6 +330,11 @@ void MainWindow::init() ui->editDeleteObjectAction->setToolTip(ui->editDeleteObjectAction->text()); }); + // When clicking the interrupt query button in the status bar, ask SQLite to interrupt the current query + connect(statusStopButton, &QToolButton::clicked, [this]() { + db.interruptQuery(); + }); + // Connect some more signals and slots connect(ui->dataTable->filterHeader(), SIGNAL(sectionClicked(int)), this, SLOT(browseTableHeaderClicked(int))); connect(ui->dataTable->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setRecordsetLabel())); @@ -332,6 +351,8 @@ void MainWindow::init() connect(ui->dataTable, &ExtendedTableWidget::selectedRowsToBeDeleted, this, &MainWindow::deleteRecord); connect(ui->actionDropQualifiedCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropQualifiedNames); connect(ui->actionEnquoteNamesCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropEnquotedNames); + connect(&db, &DBBrowserDB::databaseInUseChanged, this, &MainWindow::updateDatabaseBusyStatus); + ui->actionDropQualifiedCheck->setChecked(Settings::getValue("SchemaDock", "dropQualifiedNames").toBool()); ui->actionEnquoteNamesCheck->setChecked(Settings::getValue("SchemaDock", "dropEnquotedNames").toBool()); @@ -3541,3 +3562,10 @@ void MainWindow::printDbStructure () delete dialog; delete document; } + +void MainWindow::updateDatabaseBusyStatus(bool busy, const QString& user) +{ + statusBusyLabel->setText(tr("Busy (%1)").arg(user)); + statusBusyLabel->setVisible(busy); + statusStopButton->setVisible(busy); +} diff --git a/src/MainWindow.h b/src/MainWindow.h index 62f484d6c4..7c40694df3 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -7,12 +7,7 @@ #include #include -class QDragEnterEvent; class EditDialog; -class QIntValidator; -class QLabel; -class QModelIndex; -class QPersistentModelIndex; class SqliteTableModel; class DbStructureModel; class RemoteDock; @@ -20,6 +15,13 @@ class RemoteDatabase; class FindReplaceDialog; class ExtendedTableWidget; +class QDragEnterEvent; +class QIntValidator; +class QModelIndex; +class QLabel; +class QPersistentModelIndex; +class QToolButton; + namespace Ui { class MainWindow; } @@ -157,6 +159,8 @@ class MainWindow : public QMainWindow QLabel* statusEncodingLabel; QLabel* statusEncryptionLabel; QLabel* statusReadOnlyLabel; + QToolButton* statusStopButton; + QLabel* statusBusyLabel; DbStructureModel* dbStructureModel; @@ -301,6 +305,7 @@ private slots: void updateInsertDeleteRecordButton(); void runSqlNewTab(const QString& query, const QString& title); void printDbStructure(); + void updateDatabaseBusyStatus(bool busy, const QString& user); }; #endif diff --git a/src/icons/cancel.png b/src/icons/cancel.png new file mode 100644 index 0000000000..c149c2bc01 Binary files /dev/null and b/src/icons/cancel.png differ diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc index cff33ce5f3..a253a6ac0a 100644 --- a/src/icons/icons.qrc +++ b/src/icons/icons.qrc @@ -68,5 +68,6 @@ text_indent.png printer.png package_save.png + cancel.png diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 49fe84b6fc..aabd40a0ee 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -608,6 +608,7 @@ DBBrowserDB::db_pointer_type DBBrowserDB::get(QString user) db_user = user; db_used = true; + emit databaseInUseChanged(true, user); return db_pointer_type(_db, DatabaseReleaser(this)); } @@ -1871,3 +1872,11 @@ QString DBBrowserDB::generateTemporaryTableName(const QString& schema) const return table_name; } } + +void DBBrowserDB::interruptQuery() +{ + if(!_db) + return; + + sqlite3_interrupt(_db); +} diff --git a/src/sqlitedb.h b/src/sqlitedb.h index 027fa40ee5..ef80548c04 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -48,6 +48,7 @@ class DBBrowserDB : public QObject std::unique_lock lk(pParent->m); pParent->db_used = false; lk.unlock(); + emit pParent->databaseInUseChanged(false, QString()); pParent->cv.notify_one(); } }; @@ -111,6 +112,11 @@ class DBBrowserDB : public QObject */ bool getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, QVector& rowdata); + /** + * @brief Interrupts the currenty running statement as soon as possible. + */ + void interruptQuery(); + private: /** * @brief max Queries the table t for the max value of field. @@ -202,6 +208,7 @@ class DBBrowserDB : public QObject void dbChanged(bool dirty); void structureUpdated(); void requestCollation(QString name, int eTextRep); + void databaseInUseChanged(bool busy, QString user); private: /// external code needs to go through get() to obtain access to the database