DbStructureQItemViewFacade implemented

DbStructureQItemViewFacade provides a simple read only interface to a
QAbstractItemView (e.g. QTreeView) that holds a model() of type
DBStructureModel.

It is designed to simplify the access to the actual selected node.

The Class follows the facade design pattern.
But it doesn't control the lifecycle of the itemView it is connected to.
This commit is contained in:
horst-p-w-neubauer
2020-05-15 22:29:32 +02:00
committed by Martin Kleusberg
parent ab682a321c
commit 06dc1325b1
6 changed files with 222 additions and 43 deletions
+2
View File
@@ -145,6 +145,7 @@ set(SQLB_MOC_HDR
src/sqltextedit.h
src/docktextedit.h
src/DbStructureModel.h
src/dbstructureqitemviewfacade.h
src/Application.h
src/CipherDialog.h
src/ExportSqlDialog.h
@@ -202,6 +203,7 @@ set(SQLB_SRC
src/docktextedit.cpp
src/csvparser.cpp
src/DbStructureModel.cpp
src/dbstructureqitemviewfacade.cpp
src/main.cpp
src/Application.cpp
src/CipherDialog.cpp
+41 -43
View File
@@ -80,6 +80,8 @@ MainWindow::MainWindow(QWidget* parent)
MainWindow::~MainWindow()
{
delete dbSelected;
delete dockDbSelected;
delete ui;
}
@@ -117,6 +119,10 @@ void MainWindow::init()
});
#endif
// create facade objects to dbTreeWidgets
dbSelected = new DbStructureQItemViewFacade(*ui->dbTreeWidget);
dockDbSelected = new DbStructureQItemViewFacade(*ui->treeSchemaDock);
// Connect SQL logging and database state setting to main window
connect(&db, &DBBrowserDB::dbChanged, this, &MainWindow::dbState, Qt::QueuedConnection);
connect(&db, &DBBrowserDB::sqlExecuted, this, &MainWindow::logSql, Qt::QueuedConnection);
@@ -446,9 +452,7 @@ void MainWindow::init()
// Action for switching the table via the Database Structure tab
connect(ui->actionPopupSchemaDockBrowseTable, &QAction::triggered, [this]() {
sqlb::ObjectIdentifier obj(ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(),
ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString());
switchToBrowseDataTab(obj);
switchToBrowseDataTab(dockDbSelected->object());
refresh(); // Required in case the Browse Data tab already was the active main tab
});
@@ -842,9 +846,8 @@ void MainWindow::compact()
void MainWindow::deleteObject()
{
// Get name and type of object to delete
sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString());
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString();
sqlb::ObjectIdentifier obj = dbSelected->object();
QString type = dbSelected->objectType();
// Due to different grammar in languages (e.g. gender or declension), each message must be given separately to translation.
QString message;
@@ -858,11 +861,11 @@ void MainWindow::deleteObject()
message = tr("Are you sure you want to delete the index '%1'?");
// Ask user if he really wants to delete that table
if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(QString::fromStdString(name.name())),
if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(QString::fromStdString(obj.name())),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{
// Delete the table
QString statement = QString("DROP %1 %2;").arg(type.toUpper(), QString::fromStdString(name.toString()));
QString statement = QString("DROP %1 %2;").arg(type.toUpper(), QString::fromStdString(obj.toString()));
if(!db.executeSQL(statement.toStdString()))
{
if (type == "table")
@@ -885,13 +888,12 @@ void MainWindow::deleteObject()
void MainWindow::editObject()
{
if(!ui->dbTreeWidget->selectionModel()->hasSelection())
if(!dbSelected->hasSelection())
return;
// Get name and type of the object to edit
sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(),
ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString());
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString();
sqlb::ObjectIdentifier obj = dbSelected->object();
QString type = dbSelected->objectType();
if(type == "table")
{
@@ -912,12 +914,12 @@ void MainWindow::editObject()
db.setPragma("foreign_keys", "0");
}
EditTableDialog dialog(db, name, false, this);
EditTableDialog dialog(db, obj, false, this);
bool ok = dialog.exec();
// If foreign_keys were enabled, we must commit or rollback the transaction so the foreign_keys pragma can be restored.
if (foreign_keys == "1") {
if (!db.querySingleValueFromDb("PRAGMA " + sqlb::escapeIdentifier(name.schema()) + ".foreign_key_check").isNull()) {
if (!db.querySingleValueFromDb("PRAGMA " + sqlb::escapeIdentifier(obj.schema()) + ".foreign_key_check").isNull()) {
// Raise warning for accepted modification. When rejected, warn user also since we know now that the table has problems,
// but it wasn't our fault.
if (ok)
@@ -937,25 +939,25 @@ void MainWindow::editObject()
if(ok) {
for(const auto& t : allTableBrowserWidgets())
{
if(t->currentlyBrowsedTableName() == name)
if(t->currentlyBrowsedTableName() == obj)
t->clearFilters();
}
refreshTableBrowsers();
}
} else if(type == "index") {
EditIndexDialog dialog(db, name, false, this);
EditIndexDialog dialog(db, obj, false, this);
if(dialog.exec())
refreshTableBrowsers();
} else if(type == "view") {
sqlb::ViewPtr view = db.getObjectByName<sqlb::View>(name);
runSqlNewTab(QString("DROP VIEW %1;\n%2").arg(QString::fromStdString(name.toString())).arg(QString::fromStdString(view->sql())),
tr("Edit View %1").arg(QString::fromStdString(name.toDisplayString())),
sqlb::ViewPtr view = db.getObjectByName<sqlb::View>(obj);
runSqlNewTab(QString("DROP VIEW %1;\n%2").arg(QString::fromStdString(obj.toString())).arg(QString::fromStdString(view->sql())),
tr("Edit View %1").arg(QString::fromStdString(obj.toDisplayString())),
"https://www.sqlite.org/lang_createview.html",
/* autoRun */ false);
} else if(type == "trigger") {
sqlb::TriggerPtr trigger = db.getObjectByName<sqlb::Trigger>(name);
runSqlNewTab(QString("DROP TRIGGER %1;\n%2").arg(QString::fromStdString(name.toString())).arg(QString::fromStdString(trigger->sql())),
tr("Edit Trigger %1").arg(QString::fromStdString(name.toDisplayString())),
sqlb::TriggerPtr trigger = db.getObjectByName<sqlb::Trigger>(obj);
runSqlNewTab(QString("DROP TRIGGER %1;\n%2").arg(QString::fromStdString(obj.toString())).arg(QString::fromStdString(trigger->sql())),
tr("Edit Trigger %1").arg(QString::fromStdString(obj.toDisplayString())),
"https://www.sqlite.org/lang_createtrigger.html",
/* autoRun */ false);
}
@@ -1337,12 +1339,10 @@ void MainWindow::exportTableToCSV()
sqlb::ObjectIdentifier current_table;
if(ui->mainTab->currentWidget() == ui->structure)
{
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType)).toString();
QString type = dbSelected->objectType();
if(type == "table" || type == "view")
{
QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString();
QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString();
current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString());
current_table = dbSelected->object();
}
} else if(ui->mainTab->currentWidget() == ui->browser) {
current_table = currentlyBrowsedTableName();
@@ -1359,12 +1359,10 @@ void MainWindow::exportTableToJson()
sqlb::ObjectIdentifier current_table;
if(ui->mainTab->currentWidget() == ui->structure)
{
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType)).toString();
QString type = dbSelected->objectType();
if(type == "table" || type == "view")
{
QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString();
QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString();
current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString());
current_table = dbSelected->object();
}
} else if(ui->mainTab->currentWidget() == ui->browser) {
current_table = currentlyBrowsedTableName();
@@ -1502,11 +1500,10 @@ void MainWindow::openPreferences()
//** Db Tree Context Menu
void MainWindow::createTreeContextMenu(const QPoint &qPoint)
{
if(!ui->dbTreeWidget->selectionModel()->hasSelection())
if(!dbSelected->hasSelection())
return;
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 1)).toString();
QString type = dbSelected->objectType();
if(type == "table" || type == "view" || type == "trigger" || type == "index")
popupTableMenu->exec(ui->dbTreeWidget->mapToGlobal(qPoint));
}
@@ -1515,9 +1512,10 @@ void MainWindow::createTreeContextMenu(const QPoint &qPoint)
void MainWindow::createSchemaDockContextMenu(const QPoint &qPoint)
{
bool enable_browse_table = false;
if(ui->treeSchemaDock->selectionModel()->hasSelection())
if(dockDbSelected->hasSelection())
{
QString type = ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString();
QString type = dockDbSelected->objectType();
if(type == "table" || type == "view")
enable_browse_table = true;
}
@@ -1533,11 +1531,11 @@ void MainWindow::changeTreeSelection()
ui->editModifyObjectAction->setEnabled(false);
ui->actionEditBrowseTable->setEnabled(false);
if(!ui->dbTreeWidget->currentIndex().isValid())
if(!dbSelected->hasSelection())
return;
// Change the text and tooltips of the actions
QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 1)).toString();
QString type = dbSelected->objectType();
if (type.isEmpty())
{
@@ -3142,11 +3140,11 @@ void MainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse)
if(tableToBrowse.isEmpty())
{
// Cancel here if there is no selection
if(!ui->dbTreeWidget->selectionModel()->hasSelection())
if(!dbSelected->hasSelection())
return;
tableToBrowse.setSchema(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString());
tableToBrowse.setName(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString());
tableToBrowse.setSchema(dbSelected->schema().toStdString());
tableToBrowse.setName(dbSelected->name().toStdString());
}
TableBrowserDock* d = newTableBrowserTab(tableToBrowse);
@@ -3167,11 +3165,11 @@ void MainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse)
void MainWindow::copyCurrentCreateStatement()
{
// Cancel if no field is currently selected
if(!ui->dbTreeWidget->selectionModel()->hasSelection())
if(!dbSelected->hasSelection())
return;
// Get the CREATE statement from the Schema column
QString stmt = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 3), Qt::EditRole).toString();
// Get the CREATE statement from the SQL column
QString stmt = dbSelected->sql();
// Copy the statement to the global application clipboard
QApplication::clipboard()->setText(stmt);
+11
View File
@@ -1,6 +1,7 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "dbstructureqitemviewfacade.h"
#include "sqlitedb.h"
#include <memory>
@@ -90,6 +91,16 @@ private:
QAction* clearRecentFilesAction;
QAction* recentSeparatorAct;
/**
* @brief dbSelected provides a simple read only interface to the actual selected node of ui->dbTreeWidget
*/
DbStructureQItemViewFacade *dbSelected;
/**
* @brief dockDbSelected provides a simple read only interface to the actual selected node of ui->treeSchemaDock
*/
DbStructureQItemViewFacade *dockDbSelected;
EditDialog* editDock;
PlotDock* plotDock;
RemoteDock* remoteDock;
+59
View File
@@ -0,0 +1,59 @@
#include "DbStructureModel.h"
#include "dbstructureqitemviewfacade.h"
DbStructureQItemViewFacade::DbStructureQItemViewFacade(QAbstractItemView& aitemView)
: QObject(&aitemView),
m_itemView(aitemView)
{
}
const QAbstractItemView& DbStructureQItemViewFacade::itemView() const
{
return m_itemView;
}
bool DbStructureQItemViewFacade::hasSelection() const
{
return m_itemView.selectionModel()->hasSelection();
}
QString DbStructureQItemViewFacade::displayName() const
{
QAbstractItemModel *model = m_itemView.model();
QModelIndex index = m_itemView.currentIndex();
return model->data(index.sibling(index.row(), DbStructureModel::ColumnName), Qt::DisplayRole).toString();
}
QString DbStructureQItemViewFacade::name() const
{
QAbstractItemModel *model = m_itemView.model();
QModelIndex index = m_itemView.currentIndex();
return model->data(index.sibling(index.row(), DbStructureModel::ColumnName), Qt::EditRole).toString();
}
QString DbStructureQItemViewFacade::objectType() const
{
QAbstractItemModel *model = m_itemView.model();
QModelIndex index = m_itemView.currentIndex();
return model->data(index.sibling(index.row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString();
}
QString DbStructureQItemViewFacade::schema() const
{
QAbstractItemModel *model = m_itemView.model();
QModelIndex index = m_itemView.currentIndex();
return model->data(index.sibling(index.row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString();
}
QString DbStructureQItemViewFacade::sql() const
{
QAbstractItemModel *model = m_itemView.model();
QModelIndex index = m_itemView.currentIndex();
return model->data(index.sibling(index.row(), DbStructureModel::ColumnSQL), Qt::EditRole).toString();
}
sqlb::ObjectIdentifier DbStructureQItemViewFacade::object() const
{
return sqlb::ObjectIdentifier(schema().toStdString(), name().toStdString());
}
+107
View File
@@ -0,0 +1,107 @@
#ifndef DBSTRUCTUREQITEMVIEWFACADE_H
#define DBSTRUCTUREQITEMVIEWFACADE_H
#include <QObject>
#include <QString>
#include <QAbstractItemView>
#include <QTreeView>
#include <DbStructureModel.h>
#include <sql/ObjectIdentifier.h>
/**
* @brief The DbStructureQItemViewFacade class
* Provides a simple read only interface to a QAbstractItemView (e.g. QTreeView) that holds a model() of type DBStructureModel.
*
* It is designed to simplify the access to the actual selected node.
*
* The Class follows the facade design pattern.
* But it doesn't control the lifecycle of the itemView it is connected to.
*
*/
class DbStructureQItemViewFacade : public QObject
{
Q_OBJECT
public:
explicit DbStructureQItemViewFacade(QAbstractItemView& aitemView);
/**
* @brief itemView returns the itemView that is hiding behind the facade.
* ItemView is connected on construction, the facadeObject has to be destroyed before the itemView.
*
* @return connected itemView
*/
const QAbstractItemView& itemView() const;
/**
* @brief hasSelection returns true, if the itemView() has a selected Item.
* itemView().selectionModel().hasSelection()
*
* @return true, if the itemView() has a selected Item.
***/
bool hasSelection() const;
/**
* @brief displayName returns the displayName of the itemViews selectedItem.
*
* It is taken from the model().data() with column=ColumnName and role=Qt::DisplayRole
*
* For the display role and the browsable branch of the tree we want to show the column name including the schema name if necessary (i.e.
* for schemata != "main"). For the normal structure branch of the tree we don't want to add the schema name because it's already obvious from
* the position of the item in the tree.
*
* @return displayName of selectedItem
*/
QString displayName() const;
/**
* @brief returns the name of the itemViews selectedItem without decorations.
* It is taken from the model().data() with column=ColumnName and role=Qt::EditRole
*
* @return name of selectedItem
*/
QString name() const;
/**
* @brief objectType returns the objectType of the itemViews selectedItem.
*
* It is taken from the model().data() with column=ColumnObjectType and role=Qt::EditRole
*
* @return
*/
QString objectType() const;
/**
* @brief schema returns the schema of the itemViews selectedItem.
*
* It is taken from the model().data() with column=ColumnSchema and role=Qt::EditRole
*
* @return
*/
QString schema() const;
/**
* @brief sql returns the sql statement of the itemViews selectedItem.
*
* It is taken from the model().data() with column=ColumnSQL and role=Qt::EditRole
*
* @return
*/
QString sql() const;
/**
* @brief Object returns a sqlb::ObjectIdentifier to the selected itemView item.
* Object identifier consisting of schema name and object name.
*
* @return sqlb::ObjectIdentifier to selected item
*/
sqlb::ObjectIdentifier object() const;
private:
QAbstractItemView& m_itemView;
};
#endif
+2
View File
@@ -26,6 +26,7 @@ HEADERS += \
RemoteLocalFilesModel.h \
RemoteNetwork.h \
TableBrowserDock.h \
dbstructureqitemviewfacade.h \
sqlitedb.h \
MainWindow.h \
EditIndexDialog.h \
@@ -91,6 +92,7 @@ SOURCES += \
RemoteLocalFilesModel.cpp \
RemoteNetwork.cpp \
TableBrowserDock.cpp \
dbstructureqitemviewfacade.cpp \
sqlitedb.cpp \
MainWindow.cpp \
EditIndexDialog.cpp \