mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
This commit refactors vast parts of the sqlitetypes.h interface. Its main goals are: less code, easier code, a more modern interface, reduced likelihood for strange errors and more flexibility for future extensions. The main reason why the sqlitetypes.h functions were working so well in DB4S was not because they were that stable but because they were extremely interlinked with the rest of the code. This is fine because we do not plan to ship them as a separate library. But it makes it hard to find the obvious spot to fix an issue or to put a new function. It can always be done in the sqlitetypes function or in the rest of the DB4S code because it is just not clear what the interface between the two should look like. This is supposed to be improved by this commit. One main thing here is to make ownership of objects a bit clearer. In theory the new code should be faster too but that difference will be neglectable from a user POV. This commit also fixes a hidden bug which caused all table constraints to be removed in the Edit Table dialog when a single field was removed from the table. This is all still WIP and more work is needed to be done here.
187 lines
6.0 KiB
C++
187 lines
6.0 KiB
C++
#include "sqlitedb.h"
|
|
#include "ForeignKeyEditorDelegate.h"
|
|
|
|
#include <QComboBox>
|
|
#include <QLineEdit>
|
|
#include <QPushButton>
|
|
#include <QHBoxLayout>
|
|
|
|
class ForeignKeyEditor : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit ForeignKeyEditor(QWidget* parent = nullptr)
|
|
: QWidget(parent)
|
|
, tablesComboBox(new QComboBox(this))
|
|
, idsComboBox(new QComboBox(this))
|
|
, clauseEdit(new QLineEdit(this))
|
|
, m_btnReset(new QPushButton(tr("&Reset"), this))
|
|
{
|
|
idsComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
|
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);
|
|
layout->setSpacing(0);
|
|
layout->setMargin(0);
|
|
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)
|
|
{
|
|
for(auto it=m_db.schemata.constBegin();it!=m_db.schemata.constEnd();++it)
|
|
{
|
|
for(auto jt=it->constBegin();jt!=it->constEnd();++jt)
|
|
{
|
|
if((*jt)->type() == sqlb::Object::Types::Table)
|
|
{
|
|
QString tableName = (*jt)->name();
|
|
m_tablesIds.insert(tableName, std::dynamic_pointer_cast<sqlb::Table>(*jt)->fieldNames());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
});
|
|
|
|
editor->tablesComboBox->clear();
|
|
editor->tablesComboBox->addItems(m_tablesIds.keys());
|
|
|
|
return editor;
|
|
}
|
|
|
|
void ForeignKeyEditorDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
|
{
|
|
ForeignKeyEditor* fkEditor = static_cast<ForeignKeyEditor*>(editor);
|
|
|
|
int column = index.row(); // weird? I know right
|
|
const sqlb::Field& field = m_table.fields.at(column);
|
|
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(m_table.constraint({field.name()}, sqlb::Constraint::ForeignKeyConstraintType));
|
|
if (fk) {
|
|
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();
|
|
const sqlb::Field& field = m_table.fields.at(column);
|
|
if (sql.isEmpty()) {
|
|
// Remove the foreign key
|
|
m_table.removeConstraints({field.name()}, 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.name()}, 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);
|
|
}
|
|
|
|
void ForeignKeyEditorDelegate::updateTablesList(const QString& oldTableName)
|
|
{
|
|
// this is used for recursive table constraints when
|
|
// table column references column within same table
|
|
m_tablesIds.remove(oldTableName);
|
|
m_tablesIds.insert(m_table.name(), m_table.fieldNames());
|
|
}
|
|
|
|
#include "ForeignKeyEditorDelegate.moc"
|