From 002bc6697468d9ec84309757f64ca69c4fc5800c Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 5 Aug 2023 01:31:52 +0200 Subject: [PATCH] Data Browser: Implement undo of cell changes using non-unique savepoints See issue #3345 --- src/MainWindow.cpp | 9 ++++++++ src/MainWindow.h | 1 + src/MainWindow.ui | 49 +++++++++++++++++++++++++++++++++++++--- src/icons/icons.qrc | 1 + src/icons/undo.svg | 29 ++++++++++++++++++++++++ src/sqlitedb.cpp | 4 ++-- src/sqlitedb.h | 2 +- src/sqlitetablemodel.cpp | 2 ++ 8 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/icons/undo.svg diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 9fb102461..6263fb1dc 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1469,6 +1469,7 @@ void MainWindow::dbState(bool dirty) { ui->fileSaveAction->setEnabled(dirty); ui->fileRevertAction->setEnabled(dirty); + ui->undoAction->setEnabled(dirty); // Unfortunately, sqlite does not allow to backup the DB while there are pending savepoints, // so we cannot "Save As" when the DB is dirty. ui->fileSaveAsAction->setEnabled(!dirty); @@ -1498,6 +1499,14 @@ void MainWindow::fileRevert() } } +void MainWindow::undo() +{ + if (db.isOpen()) { + db.revertToSavepoint("DB4S_UNDO"); + refreshTableBrowsers(); + } +} + void MainWindow::exportDatabaseToSQL() { QString current_table; diff --git a/src/MainWindow.h b/src/MainWindow.h index 9529631d0..34746cfe1 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -187,6 +187,7 @@ private slots: void exportTableToJson(); void fileSave(); void fileRevert(); + void undo(); void exportDatabaseToSQL(); void importDatabaseFromSQL(); void openRecentFile(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index ec785be44..8c7b6f81c 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -183,8 +183,8 @@ You can drag SQL statements from an object row and drop them into other applicat 0 0 - 673 - 544 + 640 + 526 @@ -753,7 +753,7 @@ You can drag SQL statements from an object row and drop them into other applicat 0 0 1037 - 23 + 22 @@ -792,6 +792,7 @@ You can drag SQL statements from an object row and drop them into other applicat + @@ -882,6 +883,7 @@ You can drag SQL statements from an object row and drop them into other applicat + @@ -1254,6 +1256,30 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed QAction::NoRole + + + false + + + + :/icons/undo.svg:/icons/undo.svg + + + &Undo + + + Undo last change to a cell in the browser + + + Undo last change to a cell in the browser + + + This action is used to undo the last change performed to a cell in the database browser. Redoing is not possible. + + + QAction::NoRole + + false @@ -2530,6 +2556,22 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed + + undoAction + triggered() + MainWindow + undo() + + + -1 + -1 + + + 399 + 299 + + + fileSaveAction triggered() @@ -3903,6 +3945,7 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed importTableFromCSV() exportTableToCSV() fileRevert() + undo() fileSave() deleteIndex() createIndex() diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc index 96383cd9d..4629144ba 100644 --- a/src/icons/icons.qrc +++ b/src/icons/icons.qrc @@ -104,5 +104,6 @@ text_underlined.svg textfield_delete.svg wrench.svg + undo.svg diff --git a/src/icons/undo.svg b/src/icons/undo.svg new file mode 100644 index 000000000..cae4034b8 --- /dev/null +++ b/src/icons/undo.svg @@ -0,0 +1,29 @@ + + + + Undo + Undo + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index e7539a903..37f1e6fe3 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -564,7 +564,7 @@ void DBBrowserDB::getSqliteVersion(QString& sqlite, QString& sqlcipher) #endif } -bool DBBrowserDB::setSavepoint(const std::string& pointname) +bool DBBrowserDB::setSavepoint(const std::string& pointname, bool unique) { if(!isOpen()) return false; @@ -572,7 +572,7 @@ bool DBBrowserDB::setSavepoint(const std::string& pointname) qWarning() << "setSavepoint: not done. DB is read-only"; return false; } - if(contains(savepointList, pointname)) + if(unique && contains(savepointList, pointname)) return true; executeSQL("SAVEPOINT " + sqlb::escapeIdentifier(pointname) + ";", false, true); diff --git a/src/sqlitedb.h b/src/sqlitedb.h index aa7cb4fa7..8bf2bfab1 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -123,7 +123,7 @@ class DBBrowserDB : public QObject **/ db_pointer_type get (const QString& user, bool force_wait = false); - bool setSavepoint(const std::string& pointname = "RESTOREPOINT"); + bool setSavepoint(const std::string& pointname = "RESTOREPOINT", bool unique = true); bool releaseSavepoint(const std::string& pointname = "RESTOREPOINT"); bool revertToSavepoint(const std::string& pointname = "RESTOREPOINT"); bool releaseAllSavepoints(); diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index 31dd3f216..530484327 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -473,6 +473,8 @@ bool SqliteTableModel::setTypedData(const QModelIndex& index, bool isBlob, const return false; } + m_db.setSavepoint("DB4S_UNDO", false); + if(index.isValid() && role == Qt::EditRole) { std::unique_lock lock(m_mutexDataCache);