mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-05-08 12:59:52 -05:00
Enhanced UI for creating and editing foreign keys
This commit is contained in:
committed by
Vladyslav Tronko
parent
d8983cb066
commit
4f7473fbed
@@ -104,6 +104,7 @@ set(SQLB_MOC_HDR
|
||||
src/ColumnDisplayFormatDialog.h
|
||||
src/FilterLineEdit.h
|
||||
src/RemoteDatabase.h
|
||||
src/ForeignKeyEditorDelegate.h
|
||||
)
|
||||
|
||||
set(SQLB_SRC
|
||||
@@ -137,6 +138,7 @@ set(SQLB_SRC
|
||||
src/ColumnDisplayFormatDialog.cpp
|
||||
src/FilterLineEdit.cpp
|
||||
src/RemoteDatabase.cpp
|
||||
src/ForeignKeyEditorDelegate.cpp
|
||||
)
|
||||
|
||||
set(SQLB_FORMS
|
||||
|
||||
+6
-10
@@ -1,5 +1,6 @@
|
||||
#include "EditTableDialog.h"
|
||||
#include "Settings.h"
|
||||
#include "ForeignKeyEditorDelegate.h"
|
||||
#include "ui_EditTableDialog.h"
|
||||
#include "sqlitetablemodel.h"
|
||||
#include "sqlitedb.h"
|
||||
@@ -24,6 +25,8 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const QString& tableName, bool
|
||||
ui->widgetExtension->setVisible(false);
|
||||
connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),this,SLOT(itemChanged(QTreeWidgetItem*,int)));
|
||||
|
||||
// Set item delegate for foreign key column
|
||||
ui->treeWidget->setItemDelegateForColumn(kForeignKey, new ForeignKeyEditorDelegate(db, m_table, this));
|
||||
// Editing an existing table?
|
||||
if(m_bNewTable == false)
|
||||
{
|
||||
@@ -80,6 +83,7 @@ void EditTableDialog::updateColumnWidth()
|
||||
ui->treeWidget->setColumnWidth(kPrimaryKey, 30);
|
||||
ui->treeWidget->setColumnWidth(kAutoIncrement, 30);
|
||||
ui->treeWidget->setColumnWidth(kUnique, 30);
|
||||
ui->treeWidget->setColumnWidth(kForeignKey, 500);
|
||||
}
|
||||
|
||||
void EditTableDialog::populateFields()
|
||||
@@ -446,16 +450,8 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
|
||||
callRenameColumn = true;
|
||||
break;
|
||||
case kForeignKey:
|
||||
if(item->text(column).trimmed().isEmpty())
|
||||
{
|
||||
// Remove the foreign key
|
||||
m_table.removeConstraints({field}, sqlb::Constraint::ConstraintTypes::ForeignKeyConstraintType);
|
||||
} else {
|
||||
// Set the foreign key
|
||||
sqlb::ForeignKeyClause* fk = new sqlb::ForeignKeyClause;
|
||||
fk->setFromString(item->text(column));
|
||||
m_table.setConstraint({field}, sqlb::ConstraintPtr(fk));
|
||||
}
|
||||
// handled in delegate
|
||||
|
||||
if(!m_bNewTable)
|
||||
callRenameColumn = true;
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
#include "sqlitedb.h"
|
||||
#include "ForeignKeyEditorDelegate.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
class ForeignKeyEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ForeignKeyEditor(QWidget* parent = Q_NULLPTR)
|
||||
: QWidget(parent)
|
||||
, tablesComboBox(new QComboBox(this))
|
||||
, idsComboBox(new QComboBox(this))
|
||||
, clauseEdit(new QLineEdit(this))
|
||||
, m_btnReset(new QPushButton(tr("&Reset"), this))
|
||||
{
|
||||
clauseEdit->setPlaceholderText(tr("(foreign key clauses(ON UPDATE, ON DELETE etc.)"));
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->addWidget(tablesComboBox);
|
||||
layout->addWidget(idsComboBox);
|
||||
layout->addWidget(clauseEdit);
|
||||
layout->addWidget(m_btnReset);
|
||||
setLayout(layout);
|
||||
|
||||
connect(m_btnReset, &QPushButton::clicked, [&]
|
||||
{
|
||||
tablesComboBox->setCurrentIndex(-1);
|
||||
idsComboBox->setCurrentIndex(-1);
|
||||
clauseEdit->clear();
|
||||
});
|
||||
|
||||
connect(tablesComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||
[=](int index)
|
||||
{
|
||||
// reset ids combo box
|
||||
idsComboBox->setCurrentIndex(-1);
|
||||
|
||||
// disable clauses editor if none of tables is selected
|
||||
bool enableClausesEditor = (index!= -1);
|
||||
clauseEdit->setEnabled(enableClausesEditor);
|
||||
});
|
||||
}
|
||||
|
||||
QString getSql() const
|
||||
{
|
||||
if (tablesComboBox->currentText().isEmpty())
|
||||
return QString();
|
||||
|
||||
const QString table = sqlb::escapeIdentifier(tablesComboBox->currentText());
|
||||
const QString clauses = clauseEdit->text();
|
||||
|
||||
QString id = idsComboBox->currentText();
|
||||
if (!id.isEmpty())
|
||||
id = QString("(%1)").arg(sqlb::escapeIdentifier(id));
|
||||
|
||||
return QString("%1%2 %3")
|
||||
.arg(table)
|
||||
.arg(id)
|
||||
.arg(clauses)
|
||||
.trimmed();
|
||||
}
|
||||
|
||||
QComboBox* tablesComboBox;
|
||||
QComboBox* idsComboBox;
|
||||
QLineEdit* clauseEdit; // for ON CASCADE and such
|
||||
|
||||
private:
|
||||
QPushButton* m_btnReset;
|
||||
};
|
||||
|
||||
ForeignKeyEditorDelegate::ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::Table& table, QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
, m_db(db)
|
||||
, m_table(table)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QWidget* ForeignKeyEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(option)
|
||||
Q_UNUSED(index)
|
||||
|
||||
ForeignKeyEditor* editor = new ForeignKeyEditor(parent);
|
||||
editor->setAutoFillBackground(true);
|
||||
|
||||
connect(editor->tablesComboBox, static_cast<void(QComboBox::*)(const QString&)>(&QComboBox::currentIndexChanged),
|
||||
[=](const QString& tableName)
|
||||
{
|
||||
QComboBox* box = editor->idsComboBox;
|
||||
box->clear();
|
||||
box->addItem(QString()); // for those heroes who don't like to specify key explicitly
|
||||
box->addItems(m_tablesIds[tableName]);
|
||||
box->setCurrentIndex(0);
|
||||
});
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
void ForeignKeyEditorDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||
{
|
||||
ForeignKeyEditor* fkEditor = static_cast<ForeignKeyEditor*>(editor);
|
||||
|
||||
m_tablesIds.clear();
|
||||
const auto objects = m_db.getBrowsableObjects();
|
||||
for (auto obj : objects) {
|
||||
if ("table" == obj.gettype()) {
|
||||
QString tableName = obj.table.name();
|
||||
m_tablesIds.insert(tableName, obj.table.fieldNames());
|
||||
}
|
||||
}
|
||||
|
||||
fkEditor->tablesComboBox->addItems(m_tablesIds.keys());
|
||||
|
||||
int column = index.row(); // weird? I know right
|
||||
sqlb::FieldPtr field = m_table.fields().at(column);
|
||||
QSharedPointer<sqlb::ForeignKeyClause> fk = m_table.constraint({field}, sqlb::Constraint::ForeignKeyConstraintType).dynamicCast<sqlb::ForeignKeyClause>();
|
||||
if (!fk.isNull()) {
|
||||
fkEditor->tablesComboBox->setCurrentText(fk->table());
|
||||
fkEditor->clauseEdit->setText(fk->constraint());
|
||||
if (!fk->columns().isEmpty())
|
||||
fkEditor->idsComboBox->setCurrentText(fk->columns().first());
|
||||
} else {
|
||||
fkEditor->tablesComboBox->setCurrentIndex(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void ForeignKeyEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
|
||||
{
|
||||
ForeignKeyEditor* fkEditor = static_cast<ForeignKeyEditor*>(editor);
|
||||
QString sql = fkEditor->getSql();
|
||||
|
||||
int column = index.row();
|
||||
sqlb::FieldPtr field = m_table.fields().at(column);
|
||||
if (sql.isEmpty()) {
|
||||
// Remove the foreign key
|
||||
m_table.removeConstraints({field}, sqlb::Constraint::ConstraintTypes::ForeignKeyConstraintType);
|
||||
} else {
|
||||
// Set the foreign key
|
||||
sqlb::ForeignKeyClause* fk = new sqlb::ForeignKeyClause;
|
||||
|
||||
const QString table = fkEditor->tablesComboBox->currentText();
|
||||
const QString id = fkEditor->idsComboBox->currentText();
|
||||
const QString clause = fkEditor->clauseEdit->text();
|
||||
|
||||
fk->setTable(table);
|
||||
|
||||
if (!id.isEmpty())
|
||||
fk->setColumns({id});
|
||||
|
||||
if (!clause.trimmed().isEmpty()) {
|
||||
fk->setConstraint(clause);
|
||||
}
|
||||
|
||||
m_table.setConstraint({field}, sqlb::ConstraintPtr(fk));
|
||||
}
|
||||
|
||||
model->setData(index, sql);
|
||||
}
|
||||
|
||||
void ForeignKeyEditorDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
#include "ForeignKeyEditorDelegate.moc"
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef FOREIGNKEYDELEGATE_H
|
||||
#define FOREIGNKEYDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class DBBrowserDB;
|
||||
class QPushButton;
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
|
||||
namespace sqlb
|
||||
{
|
||||
class Table;
|
||||
}
|
||||
|
||||
class ForeignKeyEditorDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::Table& table, QObject* parent = Q_NULLPTR);
|
||||
|
||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const Q_DECL_OVERRIDE;
|
||||
void setEditorData(QWidget* editor, const QModelIndex& index) const Q_DECL_OVERRIDE;
|
||||
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const Q_DECL_OVERRIDE;
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
const DBBrowserDB& m_db;
|
||||
sqlb::Table& m_table;
|
||||
mutable QMap<QString, QStringList> m_tablesIds;
|
||||
};
|
||||
|
||||
#endif // FOREIGNKEYDELEGATE_H
|
||||
+4
-2
@@ -52,7 +52,8 @@ HEADERS += \
|
||||
FileDialog.h \
|
||||
ColumnDisplayFormatDialog.h \
|
||||
FilterLineEdit.h \
|
||||
RemoteDatabase.h
|
||||
RemoteDatabase.h \
|
||||
ForeignKeyEditorDelegate.h
|
||||
|
||||
SOURCES += \
|
||||
sqlitedb.cpp \
|
||||
@@ -83,7 +84,8 @@ SOURCES += \
|
||||
FileDialog.cpp \
|
||||
ColumnDisplayFormatDialog.cpp \
|
||||
FilterLineEdit.cpp \
|
||||
RemoteDatabase.cpp
|
||||
RemoteDatabase.cpp \
|
||||
ForeignKeyEditorDelegate.cpp
|
||||
|
||||
RESOURCES += icons/icons.qrc \
|
||||
translations/flags/flags.qrc \
|
||||
|
||||
Reference in New Issue
Block a user