From a9e6fe4ecb00214d75a6897e990fb97451765629 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sat, 10 Aug 2019 13:18:18 +0200 Subject: [PATCH] Support adding custom constraints in Edit Table dialog This adds support for adding custom constraint in the Edit Table dialog, e.g. for adding multi-column unique constraints. --- src/EditTableDialog.cpp | 83 +++++++++++++++++++++++++---------------- src/EditTableDialog.h | 1 + src/EditTableDialog.ui | 43 +++++++++++++++++++++ src/sql/sqlitetypes.cpp | 17 +++++++++ src/sql/sqlitetypes.h | 2 + 5 files changed, 113 insertions(+), 33 deletions(-) diff --git a/src/EditTableDialog.cpp b/src/EditTableDialog.cpp index 3332e6e5..5536f46b 100644 --- a/src/EditTableDialog.cpp +++ b/src/EditTableDialog.cpp @@ -6,11 +6,13 @@ #include "sqlitedb.h" #include "SelectItemsPopup.h" -#include -#include #include #include #include +#include +#include +#include + #include Q_DECLARE_METATYPE(sqlb::ConstraintPtr) @@ -30,13 +32,22 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &EditTableDialog::fieldItemChanged); connect(ui->tableConstraints, &QTableWidget::itemChanged, this, &EditTableDialog::constraintItemChanged); - // TODO Remove this once we have added support for this button - ui->buttonAddConstraint->setVisible(false); - // Set item delegate for foreign key column m_fkEditorDelegate = new ForeignKeyEditorDelegate(db, m_table, this); ui->treeWidget->setItemDelegateForColumn(kForeignKey, m_fkEditorDelegate); + // Set up popup menu for adding constraints + QMenu* constraint_menu = new QMenu(this); + constraint_menu->addAction(ui->actionAddPrimaryKey); + constraint_menu->addAction(ui->actionAddForeignKey); + constraint_menu->addAction(ui->actionAddUniqueConstraint); + constraint_menu->addAction(ui->actionAddCheckConstraint); + connect(ui->actionAddPrimaryKey, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::PrimaryKeyConstraintType); }); + connect(ui->actionAddForeignKey, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::ForeignKeyConstraintType); }); + connect(ui->actionAddUniqueConstraint, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::UniqueConstraintType); }); + connect(ui->actionAddCheckConstraint, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::CheckConstraintType); }); + ui->buttonAddConstraint->setMenu(constraint_menu); + // Editing an existing table? if(m_bNewTable == false) { @@ -241,38 +252,21 @@ void EditTableDialog::populateConstraints() // Handle change of constraint type. Effectively this means removing the old constraint and replacing it by an entirely new one. // Only the column list and the name can be migrated to the new constraint. - // Create new constraint depending on selected type - sqlb::ConstraintPtr new_constraint; - switch(index) + // Make sure there is only one primary key at a time + if(index == 0 && !m_table.primaryKey().empty()) { - case 0: - // Make sure there is only one primary key at a time - if(!m_table.primaryKey().empty()) - { - QMessageBox::warning(this, qApp->applicationName(), tr("There can only be one primary key for each table. Please modify the existing primary " - "key instead.")); + QMessageBox::warning(this, qApp->applicationName(), tr("There can only be one primary key for each table. Please modify the existing primary " + "key instead.")); - // Set combo box back to original constraint type - type->blockSignals(true); - type->setCurrentIndex(constraint->type()); - type->blockSignals(false); - return; - } - - new_constraint = sqlb::ConstraintPtr(new sqlb::PrimaryKeyConstraint()); - break; - case 1: - new_constraint = sqlb::ConstraintPtr(new sqlb::UniqueConstraint()); - break; - case 2: - new_constraint = sqlb::ConstraintPtr(new sqlb::ForeignKeyClause()); - break; - case 3: - new_constraint = sqlb::ConstraintPtr(new sqlb::CheckConstraint()); - break; - default: + // Set combo box back to original constraint type + type->blockSignals(true); + type->setCurrentIndex(constraint->type()); + type->blockSignals(false); return; } + + // Create new constraint depending on selected type + sqlb::ConstraintPtr new_constraint = sqlb::Constraint::makeConstraint(static_cast(index)); new_constraint->setName(constraint->name()); new_constraint->column_list = constraint->column_list; @@ -907,3 +901,26 @@ void EditTableDialog::removeConstraint() updateSqlText(); populateFields(); } + +void EditTableDialog::addConstraint(sqlb::Constraint::ConstraintTypes type) +{ + // There can only be one primary key + if(type == sqlb::Constraint::PrimaryKeyConstraintType) + { + if(!m_table.primaryKey().empty()) + { + QMessageBox::information(this, qApp->applicationName(), tr("There can only be one primary key for each table. Please modify the existing primary " + "key instead.")); + return; + } + } + + // Create new constraint + sqlb::ConstraintPtr constraint = sqlb::Constraint::makeConstraint(type); + m_table.addConstraint(constraint); + + // Update SQL and view + populateFields(); + populateConstraints(); + updateSqlText(); +} diff --git a/src/EditTableDialog.h b/src/EditTableDialog.h index 1a77695b..7dd11821 100644 --- a/src/EditTableDialog.h +++ b/src/EditTableDialog.h @@ -73,6 +73,7 @@ private slots: void setWithoutRowid(bool without_rowid); void changeSchema(const QString& schema); void removeConstraint(); + void addConstraint(sqlb::Constraint::ConstraintTypes type); private: Ui::EditTableDialog* ui; diff --git a/src/EditTableDialog.ui b/src/EditTableDialog.ui index 6dcf8637..23c64d5b 100644 --- a/src/EditTableDialog.ui +++ b/src/EditTableDialog.ui @@ -300,6 +300,9 @@ :/icons/field_add:/icons/field_add + + QToolButton::InstantPopup + Qt::ToolButtonTextBesideIcon @@ -401,6 +404,46 @@ + + + + :/icons/field_key:/icons/field_key + + + Primary Key + + + Add a primary key constraint + + + + + + :/icons/field_fk:/icons/field_fk + + + Foreign Key + + + Add a foreign key constraint + + + + + Unique + + + Add a unique constraint + + + + + Check + + + Add a check constraint + + diff --git a/src/sql/sqlitetypes.cpp b/src/sql/sqlitetypes.cpp index 1a3db815..233199fc 100644 --- a/src/sql/sqlitetypes.cpp +++ b/src/sql/sqlitetypes.cpp @@ -131,6 +131,23 @@ std::string Object::typeToString(Types type) return ""; } +ConstraintPtr Constraint::makeConstraint(ConstraintTypes type) +{ + switch(type) + { + case PrimaryKeyConstraintType: + return sqlb::ConstraintPtr(new sqlb::PrimaryKeyConstraint()); + case UniqueConstraintType: + return sqlb::ConstraintPtr(new sqlb::UniqueConstraint()); + case ForeignKeyConstraintType: + return sqlb::ConstraintPtr(new sqlb::ForeignKeyClause()); + case CheckConstraintType: + return sqlb::ConstraintPtr(new sqlb::CheckConstraint()); + default: + return nullptr; + } +} + bool ForeignKeyClause::isSet() const { return m_override.size() || m_table.size(); diff --git a/src/sql/sqlitetypes.h b/src/sql/sqlitetypes.h index c93bc61f..5be94213 100644 --- a/src/sql/sqlitetypes.h +++ b/src/sql/sqlitetypes.h @@ -134,6 +134,8 @@ public: } virtual ~Constraint() {} + static ConstraintPtr makeConstraint(ConstraintTypes type); + virtual ConstraintTypes type() const = 0; void setName(const std::string& name) { m_name = name; }