diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 52082a33..560cc713 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -311,6 +311,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); @@ -341,6 +355,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())); @@ -357,6 +376,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()); @@ -3682,3 +3703,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 ebb80fb8..1eaef302 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -10,12 +10,7 @@ #include #include -class QDragEnterEvent; class EditDialog; -class QIntValidator; -class QLabel; -class QModelIndex; -class QPersistentModelIndex; class SqliteTableModel; class DbStructureModel; class RemoteDock; @@ -23,6 +18,13 @@ class RemoteDatabase; class FindReplaceDialog; class ExtendedTableWidget; +class QDragEnterEvent; +class QIntValidator; +class QModelIndex; +class QLabel; +class QPersistentModelIndex; +class QToolButton; + namespace Ui { class MainWindow; } @@ -158,6 +160,8 @@ private: QLabel* statusEncodingLabel; QLabel* statusEncryptionLabel; QLabel* statusReadOnlyLabel; + QToolButton* statusStopButton; + QLabel* statusBusyLabel; DbStructureModel* dbStructureModel; @@ -306,6 +310,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 00000000..c149c2bc Binary files /dev/null and b/src/icons/cancel.png differ diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc index cff33ce5..a253a6ac 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 9aaf1ab2..5fb7f4b0 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)); } @@ -1896,3 +1897,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 677b266e..554ed79b 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -48,6 +48,7 @@ private: 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 @@ public: */ 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 @@ signals: 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