From 29635e9e80d8bb2bc0e60c83f484555a10d6d454 Mon Sep 17 00:00:00 2001 From: horst-p-w-neubauer Date: Tue, 12 May 2020 01:59:05 +0200 Subject: [PATCH] detach additional database connection See issue #2239 --- src/DbStructureModel.cpp | 3 ++ src/MainWindow.cpp | 53 ++++++++++++++++++++++++++++- src/MainWindow.h | 3 ++ src/MainWindow.ui | 42 +++++++++++++++++++++++ src/icons/database_link_broken.png | Bin 0 -> 803 bytes src/icons/icons.qrc | 1 + src/sqlitedb.cpp | 27 +++++++++++++++ src/sqlitedb.h | 7 ++++ 8 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/icons/database_link_broken.png diff --git a/src/DbStructureModel.cpp b/src/DbStructureModel.cpp index c8a4db40..92f45c33 100644 --- a/src/DbStructureModel.cpp +++ b/src/DbStructureModel.cpp @@ -168,6 +168,7 @@ void DbStructureModel::reloadData() itemAll->setIcon(ColumnName, IconCache::get("database")); itemAll->setText(ColumnName, tr("All")); itemAll->setText(ColumnObjectType, "database"); + itemAll->setText(ColumnSchema, "main"); buildTree(itemAll, "main"); // Add the temporary database as a node if it isn't empty. Make sure it's always second if it exists. @@ -177,6 +178,7 @@ void DbStructureModel::reloadData() itemTemp->setIcon(ColumnName, IconCache::get("database")); itemTemp->setText(ColumnName, tr("Temporary")); itemTemp->setText(ColumnObjectType, "database"); + itemTemp->setText(ColumnSchema, "temp"); buildTree(itemTemp, "temp"); } @@ -190,6 +192,7 @@ void DbStructureModel::reloadData() itemSchema->setIcon(ColumnName, IconCache::get("database")); itemSchema->setText(ColumnName, QString::fromStdString(it.first)); itemSchema->setText(ColumnObjectType, "database"); + itemSchema->setText(ColumnSchema, QString::fromStdString(it.first)); buildTree(itemSchema, it.first); } } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 808a30cd..f41d7cdb 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -240,12 +240,14 @@ void MainWindow::init() popupTableMenu->addAction(ui->actionEditBrowseTable); popupTableMenu->addAction(ui->editModifyObjectAction); popupTableMenu->addAction(ui->editDeleteObjectAction); + popupTableMenu->addAction(ui->fileDetachAction); popupTableMenu->addSeparator(); popupTableMenu->addAction(ui->actionEditCopyCreateStatement); popupTableMenu->addAction(ui->actionExportCsvPopup); popupSchemaDockMenu = new QMenu(this); popupSchemaDockMenu->addAction(ui->actionPopupSchemaDockBrowseTable); + popupSchemaDockMenu->addAction(ui->actionPopupSchemaDockDetachDatabase); popupSchemaDockMenu->addSeparator(); popupSchemaDockMenu->addAction(ui->actionDropQualifiedCheck); popupSchemaDockMenu->addAction(ui->actionEnquoteNamesCheck); @@ -1503,7 +1505,7 @@ void MainWindow::createTreeContextMenu(const QPoint &qPoint) return; QString type = dbSelected->objectType(); - if(type == "table" || type == "view" || type == "trigger" || type == "index") + if(type == "table" || type == "view" || type == "trigger" || type == "index" || type == "database") { // needed for first click on treeView as for first time change QItemSelectionModel::currentChanged doesn't fire changeTreeSelection(); @@ -1515,14 +1517,18 @@ void MainWindow::createTreeContextMenu(const QPoint &qPoint) void MainWindow::createSchemaDockContextMenu(const QPoint &qPoint) { bool enable_browse_table = false; + bool enable_detach_file = false; if(dockDbSelected->hasSelection()) { QString type = dockDbSelected->objectType(); if(type == "table" || type == "view") enable_browse_table = true; + else if(type == "database" && dockDbSelected->schema() != "main" && dockDbSelected->schema() != "temp") + enable_detach_file = true; } ui->actionPopupSchemaDockBrowseTable->setEnabled(enable_browse_table); + ui->actionPopupSchemaDockDetachDatabase->setEnabled(enable_detach_file); popupSchemaDockMenu->exec(ui->treeSchemaDock->mapToGlobal(qPoint)); } @@ -1533,12 +1539,18 @@ void MainWindow::changeTreeSelection() ui->editDeleteObjectAction->setEnabled(false); ui->editModifyObjectAction->setEnabled(false); ui->actionEditBrowseTable->setEnabled(false); + ui->actionExportCsvPopup->setEnabled(false); + ui->fileDetachAction->setEnabled(false); + ui->actionEditCopyCreateStatement->setEnabled(false); + + ui->fileDetachAction->setVisible(false); if(!dbSelected->hasSelection()) return; // Change the text and tooltips of the actions QString type = dbSelected->objectType(); + QString schema = dbSelected->schema(); if (type.isEmpty()) { @@ -1561,15 +1573,24 @@ void MainWindow::changeTreeSelection() } else if(type == "table") { ui->editDeleteObjectAction->setText(tr("Delete Table")); ui->editModifyObjectAction->setText(tr("Modify Table")); + } else if(type == "database") { + ui->editDeleteObjectAction->setVisible(false); + ui->editModifyObjectAction->setVisible(false); + ui->fileDetachAction->setVisible(true); + ui->fileDetachAction->setEnabled(!(schema == "main" || schema == "temp")); + return; } else { // Nothing to do for other types. Set the buttons not visible and return. ui->editDeleteObjectAction->setVisible(false); ui->editModifyObjectAction->setVisible(false); + ui->fileDetachAction->setVisible(false); + ui->actionEditCopyCreateStatement->setEnabled(true); return; } ui->editDeleteObjectAction->setVisible(true); ui->editModifyObjectAction->setVisible(true); + ui->actionEditCopyCreateStatement->setEnabled(true); // Activate actions ui->editDeleteObjectAction->setEnabled(!db.readOnly()); @@ -3165,6 +3186,36 @@ void MainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse) d->raise(); } +void MainWindow::fileDetachDbTree() +{ + fileDetachTreeViewSelected(ui->dbTreeWidget); +} + +void MainWindow::fileDetachTreeSchemaDock() +{ + fileDetachTreeViewSelected(ui->treeSchemaDock); +} + +void MainWindow::fileDetachTreeViewSelected(QTreeView* treeView) +{ + if (!treeView || !treeView->selectionModel()->hasSelection()) + { + return; + } + + sqlb::ObjectIdentifier attachedDatabase = sqlb::ObjectIdentifier(); + // get the currently selected attached database from treeView parameter + // Cancel here if there is no selection + attachedDatabase.setSchema(treeView->model()->data(treeView->currentIndex().sibling(treeView->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString()); + attachedDatabase.setName(treeView->model()->data(treeView->currentIndex().sibling(treeView->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + + QString attached_as = QString::fromStdString(attachedDatabase.name()); + if (db.detach(attached_as)) + { + isProjectModified = true; + } +} + void MainWindow::copyCurrentCreateStatement() { // Cancel if no field is currently selected diff --git a/src/MainWindow.h b/src/MainWindow.h index 16cda19f..b99e84b8 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -154,6 +154,9 @@ public slots: void refresh(); void switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse = sqlb::ObjectIdentifier()); void populateStructure(const std::vector& old_tables = {}); + void fileDetachDbTree(); + void fileDetachTreeSchemaDock(); + void fileDetachTreeViewSelected(QTreeView* treeView); void reloadSettings(); bool closeFiles(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 10be4d0b..24979d9b 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -2195,6 +2195,30 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed Ctrl+Shift+F4 + + + + :/icons/db_detach:/icons/db_detach + + + Detach Database + + + Detach database file attached to the current database connection + + + + + + :/icons/db_detach:/icons/db_detach + + + Detach Database + + + Detach database file attached to the current database connection + + @@ -2913,6 +2937,22 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed + + fileDetachAction + triggered() + MainWindow + fileDetachDbTree() + + + -1 + -1 + + + 499 + 314 + + + actionEncryption triggered() @@ -3658,6 +3698,8 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed loadProject() saveProject() fileAttach() + fileDetachDbTree() + fileDetachTreeSchemaDock() editEncryption() saveSqlFileAs() switchToBrowseDataTab() diff --git a/src/icons/database_link_broken.png b/src/icons/database_link_broken.png new file mode 100644 index 0000000000000000000000000000000000000000..780ececf6ffc65b1e5ac2e91644afb6c8e260b09 GIT binary patch literal 803 zcmV+;1Kj+HP)IItmjVG#5Ogx7Y_MIi)U zCv{a`NEZc}EK*iPsH}m|SRw4^+4|aa&K=!3$M4(KMq<)M&(-r@ydR$Dg%|iwS^gXn ziG-bqZV^$ObAFMC28f7r&NqqZ2j~1L=lp#%8a+AzNF)-Mi0Fmi@4wRB-3>{S;BvV@ zM5x#6Xfztg=ks8UeI%mWu~@8hEXwlo@`qe5N1SsyO@?7mDwU#zg@xzsJ!{(#(QqIT z_-E%}FbK~1&Gu|-8_qe12-Rv84u=DFyB(q^f{37L8fvu~N~IDakq9{FI2B;C+3>5j zgO@3e>%BT$f`KpQ}*w}rRgZ5X|D!YTU&!^n#g1_h{a+MMG>m1S~fN|9_90Se+Q7wX3uDvhKY#@%+1XqolZlR zWsHrDfry~0DrRSAp{go^!Js}mI$BW_monitor_link.png server_add.png cut.png + database_link_broken.png diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index bbd17e46..746e7ba5 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -271,6 +271,33 @@ bool DBBrowserDB::open(const QString& db, bool readOnly) } } +/** + detaches a previously attached database identified with its alias-name +**/ +bool DBBrowserDB::detach(const QString& attached_as) +{ + if(!_db) + { + return false; + } + + waitForDbRelease(); + + // dettach database + if(!executeSQL("DETACH " + sqlb::escapeIdentifier(attached_as.toStdString()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + + + // Update schema to load database schema of the newly attached database + updateSchema(); + + return true; +} + + bool DBBrowserDB::attach(const QString& filePath, QString attach_as) { if(!_db) diff --git a/src/sqlitedb.h b/src/sqlitedb.h index 87e5f91a..182961eb 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -71,6 +71,13 @@ public: bool open(const QString& db, bool readOnly = false); bool attach(const QString& filename, QString attach_as = QString()); + + /** + detaches a previously attached database identified with its alias-name + + \param attached_as the alias-name as witch a additional database file has been attached to the connection + **/ + bool detach(const QString& attached_as); bool create ( const QString & db); bool close();