diff options
| author | 2014-12-06 17:33:25 -0500 | |
|---|---|---|
| committer | 2014-12-06 17:33:25 -0500 | |
| commit | 7167ce41b61d2ba2cdb526777a4233eb84a3b66a (patch) | |
| tree | a35c14143716e1f2c98f808c81f89426045a946f /SQLiteStudio3/guiSQLiteStudio/constraints | |
Imported Upstream version 2.99.6upstream/2.99.6
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/constraints')
39 files changed, 3681 insertions, 0 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columncheckpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columncheckpanel.cpp new file mode 100644 index 0000000..8402c21 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columncheckpanel.cpp @@ -0,0 +1,56 @@ +#include "columncheckpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "parser/parser.h" +#include <QDebug> + +ColumnCheckPanel::ColumnCheckPanel(QWidget *parent) : + ConstraintCheckPanel(parent) +{ +} + +SqliteExpr* ColumnCheckPanel::readExpr() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + return constr->expr; +} + +QString ColumnCheckPanel::readName() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + return constr->name; +} + +void ColumnCheckPanel::storeType() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::CHECK; +} + +SqliteConflictAlgo ColumnCheckPanel::readConflictAlgo() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + return constr->onConflict; +} + +void ColumnCheckPanel::storeExpr(SqliteExpr* expr) +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->expr = expr; +} + +void ColumnCheckPanel::storeName(const QString& name) +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->name = name; +} + +void ColumnCheckPanel::storeConflictAlgo(SqliteConflictAlgo algo) +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->onConflict = algo; +} + +SqliteCreateTable* ColumnCheckPanel::getCreateTable() +{ + return dynamic_cast<SqliteCreateTable*>(constraint->parentStatement()->parentStatement()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columncheckpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columncheckpanel.h new file mode 100644 index 0000000..8c23770 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columncheckpanel.h @@ -0,0 +1,27 @@ +#ifndef COLUMNCHECKPANEL_H +#define COLUMNCHECKPANEL_H + +#include "constraintcheckpanel.h" +#include "constraintpanel.h" +#include "guiSQLiteStudio_global.h" +#include <QWidget> + +class GUI_API_EXPORT ColumnCheckPanel : public ConstraintCheckPanel +{ + Q_OBJECT + + public: + explicit ColumnCheckPanel(QWidget *parent = 0); + + protected: + SqliteExpr* readExpr(); + QString readName(); + void storeType(); + SqliteConflictAlgo readConflictAlgo(); + void storeExpr(SqliteExpr* expr); + void storeName(const QString& name); + void storeConflictAlgo(SqliteConflictAlgo algo); + SqliteCreateTable* getCreateTable(); +}; + +#endif // COLUMNCHECKPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp new file mode 100644 index 0000000..de78b2b --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp @@ -0,0 +1,107 @@ +#include "columncollatepanel.h" +#include "ui_columncollatepanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "schemaresolver.h" +#include "uiutils.h" +#include <QStringListModel> + +ColumnCollatePanel::ColumnCollatePanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::ColumnCollatePanel) +{ + ui->setupUi(this); + init(); +} + +ColumnCollatePanel::~ColumnCollatePanel() +{ + delete ui; +} + +void ColumnCollatePanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void ColumnCollatePanel::init() +{ + collationModel = new QStringListModel(this); + ui->collationCombo->setModel(collationModel); + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->collationCombo->lineEdit(), SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + updateState(); +} + +void ColumnCollatePanel::readConstraint() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + ui->collationCombo->setCurrentText(constr->collationName); + + if (!constr->name.isNull()) + { + ui->namedCheck->setChecked(true); + ui->namedEdit->setText(constr->name); + } +} + +void ColumnCollatePanel::readCollations() +{ + SchemaResolver resolver(db); + QStringList collList = resolver.getCollations(); + + if (collList.size() > 0) + collList.prepend(""); + + collationModel->setStringList(collList); +} + +void ColumnCollatePanel::updateState() +{ + ui->namedEdit->setEnabled(ui->namedCheck->isChecked()); +} + +bool ColumnCollatePanel::validate() +{ + bool nameOk = true; + if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty()) + nameOk = false; + + bool collationOk = !ui->collationCombo->currentText().isEmpty(); + + setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint.")); + setValidState(ui->collationCombo, collationOk, tr("Enter a collation name.")); + + return nameOk && collationOk; +} + +void ColumnCollatePanel::constraintAvailable() +{ + if (constraint.isNull()) + return; + + readCollations(); + readConstraint(); +} + +void ColumnCollatePanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::COLLATE; + + if (ui->namedCheck->isChecked()) + constr->name = ui->namedEdit->text(); + + constr->collationName = ui->collationCombo->currentText(); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.h new file mode 100644 index 0000000..a7afb54 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.h @@ -0,0 +1,40 @@ +#ifndef COLUMNCOLLATEPANEL_H +#define COLUMNCOLLATEPANEL_H + +#include "constraintpanel.h" +#include "guiSQLiteStudio_global.h" + +namespace Ui { + class ColumnCollatePanel; +} + +class QStringListModel; + +class GUI_API_EXPORT ColumnCollatePanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit ColumnCollatePanel(QWidget *parent = 0); + ~ColumnCollatePanel(); + + bool validate(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + + private: + void init(); + void readConstraint(); + void readCollations(); + + QStringListModel* collationModel = nullptr; + Ui::ColumnCollatePanel *ui = nullptr; + + private slots: + void updateState(); +}; + +#endif // COLUMNCOLLATEPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.ui new file mode 100644 index 0000000..a481875 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.ui @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ColumnCollatePanel</class> + <widget class="QWidget" name="ColumnCollatePanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>79</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="collationWidget" native="true"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>30</height> + </size> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="collationLabel"> + <property name="text"> + <string>Collation name:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="collationCombo"> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="namedCheck"> + <property name="text"> + <string>Named constraint:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedEdit"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp new file mode 100644 index 0000000..3d7090a --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp @@ -0,0 +1,204 @@ +#include "columndefaultpanel.h" +#include "ui_columndefaultpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "parser/parser.h" +#include "parser/keywords.h" +#include "uiutils.h" +#include <QDebug> + +ColumnDefaultPanel::ColumnDefaultPanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::ColumnDefaultPanel) +{ + ui->setupUi(this); + init(); +} + +ColumnDefaultPanel::~ColumnDefaultPanel() +{ + delete ui; +} + +void ColumnDefaultPanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + + +bool ColumnDefaultPanel::validate() +{ + bool nameOk = true; + if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty()) + nameOk = false; + + bool exprOk = !ui->exprEdit->toPlainText().trimmed().isEmpty() && + !ui->exprEdit->haveErrors(); + + bool exprCheckedOk = exprOk && ui->exprEdit->isSyntaxChecked(); + + setValidState(ui->exprEdit, exprOk, tr("Enter a default value expression.")); + setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint.")); + + return exprCheckedOk && nameOk; +} + +bool ColumnDefaultPanel::validateOnly() +{ + ui->exprEdit->checkSyntaxNow(); + return validate(); +} + +void ColumnDefaultPanel::constraintAvailable() +{ + if (constraint.isNull()) + return; + + readConstraint(); + updateVirtualSql(); +} + +void ColumnDefaultPanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::DEFAULT; + + SqliteExprPtr expr = parseExpression(ui->exprEdit->toPlainText()); + SqliteExpr* newExpr = new SqliteExpr(*expr.data()); + newExpr->setParent(constraint.data()); + constr->expr = newExpr; + + if (ui->namedCheck->isChecked()) + constr->name = ui->namedEdit->text(); +} + +void ColumnDefaultPanel::init() +{ + setFocusProxy(ui->exprEdit); + ui->exprEdit->setShowLineNumbers(false); + + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->exprEdit, SIGNAL(textChanged()), this, SIGNAL(updateValidation())); + connect(ui->exprEdit, SIGNAL(errorsChecked(bool)), this, SIGNAL(updateValidation())); + + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + + updateState(); +} + +void ColumnDefaultPanel::readConstraint() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + + if (constr->expr) + ui->exprEdit->setPlainText(constr->expr->detokenize()); + else if (!constr->literalValue.isNull()) + ui->exprEdit->setPlainText(constr->literalValue.toString()); + + if (!constr->name.isNull()) + { + ui->namedCheck->setChecked(true); + ui->namedEdit->setText(constr->name); + } +} + +void ColumnDefaultPanel::updateVirtualSql() +{ + ui->exprEdit->setDb(db); + + SqliteCreateTable::Column* column = dynamic_cast<SqliteCreateTable::Column*>(constraint->parentStatement()); + SqliteCreateTable* createTable = dynamic_cast<SqliteCreateTable*>(column->parentStatement()); + + createTable->rebuildTokens(); + TokenList tokens = createTable->tokens; + TokenList colTokens = column->tokens; + if (createTable->columns.indexOf(column) == -1) + { + if (createTable->columns.size() == 0) + { + // No columns. Cannot get any context info. + return; + } + + colTokens = createTable->columns.last()->tokens; + } + + if (colTokens.size() == 0) + { + qWarning() << "CREATE TABLE tokens are invalid (0) while call to ColumnDefaultPanel::updateVirtualSql()."; + return; + } + + int idx = tokens.lastIndexOf(colTokens.last()); + if (idx == -1) + { + qWarning() << "CREATE TABLE tokens are invalid while call to ColumnDefaultPanel::updateVirtualSql()."; + return; + } + idx++; + + TokenList newTokens; + newTokens << TokenPtr::create(Token::SPACE, " ") + << TokenPtr::create(Token::KEYWORD, "DEFAULT") + << TokenPtr::create(Token::SPACE, " "); + + if (constraint->dialect == Dialect::Sqlite3) + { + newTokens << TokenPtr::create(Token::PAR_LEFT, "(") + << TokenPtr::create(Token::OTHER, "%1") + << TokenPtr::create(Token::PAR_RIGHT, ")"); + } + else + { + newTokens << TokenPtr::create(Token::OTHER, "%1"); + } + + tokens.insert(idx, newTokens); + QString sql = tokens.detokenize(); + + ui->exprEdit->setVirtualSqlExpression(sql); +} + +SqliteExprPtr ColumnDefaultPanel::parseExpression(const QString& sql) +{ + Parser parser(db->getDialect()); + if (!parser.parse("SELECT "+sql)) + return SqliteExprPtr(); + + QList<SqliteQueryPtr> queries = parser.getQueries(); + if (queries.size() == 0) + return SqliteExprPtr(); + + SqliteQueryPtr first = queries.first(); + if (first->queryType != SqliteQueryType::Select) + return SqliteExprPtr(); + + SqliteSelectPtr select = first.dynamicCast<SqliteSelect>(); + if (select->coreSelects.size() < 1) + return SqliteExprPtr(); + + SqliteSelect::Core* core = select->coreSelects.first(); + if (core->resultColumns.size() < 1) + return SqliteExprPtr(); + + SqliteSelect::Core::ResultColumn* resCol = core->resultColumns.first(); + if (!resCol->expr) + return SqliteExprPtr(); + + return resCol->expr->detach().dynamicCast<SqliteExpr>(); +} + +void ColumnDefaultPanel::updateState() +{ + ui->namedEdit->setEnabled(ui->namedCheck->isChecked()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.h new file mode 100644 index 0000000..933c2dd --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.h @@ -0,0 +1,41 @@ +#ifndef COLUMNDEFAULTPANEL_H +#define COLUMNDEFAULTPANEL_H + +#include "constraintpanel.h" +#include "parser/ast/sqliteconflictalgo.h" +#include "guiSQLiteStudio_global.h" +#include <QWidget> + +namespace Ui { + class ColumnDefaultPanel; +} + +class GUI_API_EXPORT ColumnDefaultPanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit ColumnDefaultPanel(QWidget *parent = 0); + ~ColumnDefaultPanel(); + + bool validate(); + bool validateOnly(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + + private: + void init(); + void readConstraint(); + void updateVirtualSql(); + SqliteExprPtr parseExpression(const QString& sql); + + Ui::ColumnDefaultPanel *ui = nullptr; + + private slots: + void updateState(); +}; + +#endif // COLUMNDEFAULTPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.ui new file mode 100644 index 0000000..fdf55b0 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.ui @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ColumnDefaultPanel</class> + <widget class="QWidget" name="ColumnDefaultPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>169</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="exprGroup"> + <property name="title"> + <string>Default value:</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="SqlEditor" name="exprEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QCheckBox" name="namedCheck"> + <property name="text"> + <string>Named constraint:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedEdit"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>SqlEditor</class> + <extends>QPlainTextEdit</extends> + <header>sqleditor.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp new file mode 100644 index 0000000..cf234f7 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp @@ -0,0 +1,266 @@ +#include "columnforeignkeypanel.h" +#include "ui_columnforeignkeypanel.h" +#include "schemaresolver.h" +#include "uiutils.h" +#include <QDebug> +#include <QSignalMapper> + +ColumnForeignKeyPanel::ColumnForeignKeyPanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::ColumnForeignKeyPanel) +{ + ui->setupUi(this); + init(); +} + +ColumnForeignKeyPanel::~ColumnForeignKeyPanel() +{ + delete ui; +} + +void ColumnForeignKeyPanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + + +bool ColumnForeignKeyPanel::validate() +{ + bool tableOk = (ui->fkTableCombo->currentIndex() > -1); + bool columnOk = (ui->fkColumnCombo->currentIndex() > -1); + bool nameOk = !ui->namedCheckBox->isChecked() || !ui->nameEdit->text().isEmpty(); + + setValidState(ui->fkTableCombo, tableOk, tr("Pick the foreign table.")); + setValidState(ui->fkColumnCombo, columnOk, tr("Pick the foreign column.")); + setValidState(ui->nameEdit, nameOk, tr("Enter a name of the constraint.")); + + return tableOk && columnOk && nameOk; +} + +void ColumnForeignKeyPanel::constraintAvailable() +{ + readTables(); + readConstraint(); +} + +void ColumnForeignKeyPanel::init() +{ + setFocusProxy(ui->fkTableCombo); + + ui->fkColumnCombo->setModel(&fkColumnsModel); + connect(ui->fkColumnCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateValidation())); + + connect(ui->namedCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->nameEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->fkTableCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateValidation())); + connect(ui->fkTableCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFkColumns())); + connect(ui->fkTableCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateState())); + connect(ui->onDeleteCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->onUpdateCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->matchCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + + ui->deferrableCombo->addItems({ + "", + sqliteDeferrable(SqliteDeferrable::DEFERRABLE), + sqliteDeferrable(SqliteDeferrable::NOT_DEFERRABLE) + }); + ui->initiallyCombo->addItems({ + "", + sqliteInitially(SqliteInitially::DEFERRED), + sqliteInitially(SqliteInitially::IMMEDIATE), + }); + + QStringList reactions = { + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::NO_ACTION), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::SET_NULL), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::SET_DEFAULT), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::CASCADE), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::RESTRICT) + }; + ui->onUpdateCombo->addItems(reactions); + ui->onDeleteCombo->addItems(reactions); + ui->matchCombo->addItems({"SIMPLE", "FULL", "PARTIAL"}); + + connect(ui->namedCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + updateState(); +} + +void ColumnForeignKeyPanel::updateState() +{ + bool tableSelected = (ui->fkTableCombo->currentIndex() > -1); + ui->fkColumnCombo->setEnabled(tableSelected); + ui->deferrableCombo->setEnabled(tableSelected); + ui->initiallyCombo->setEnabled(tableSelected); + ui->namedCheckBox->setEnabled(tableSelected); + ui->nameEdit->setEnabled(tableSelected && ui->namedCheckBox->isChecked()); + ui->onDeleteCheckBox->setEnabled(tableSelected); + ui->onUpdateCheckBox->setEnabled(tableSelected); + ui->matchCheckBox->setEnabled(tableSelected); + ui->onDeleteCombo->setEnabled(tableSelected && ui->onDeleteCheckBox->isChecked()); + ui->onUpdateCombo->setEnabled(tableSelected && ui->onUpdateCheckBox->isChecked()); + ui->matchCombo->setEnabled(tableSelected && ui->matchCheckBox->isChecked()); +} + +void ColumnForeignKeyPanel::updateFkColumns() +{ + QStringList columns; + if (ui->fkTableCombo->currentIndex() == -1) + { + fkColumnsModel.setStringList(columns); + updateState(); + return; + } + + SchemaResolver resolver(db); + columns = resolver.getTableColumns(ui->fkTableCombo->currentText()); // TODO named db attach not supported + fkColumnsModel.setStringList(columns); +} + +void ColumnForeignKeyPanel::readConstraint() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Column* column = dynamic_cast<SqliteCreateTable::Column*>(constraint->parent()); + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + if (!constr->foreignKey) + return; + + // Table + if (!constr->foreignKey->foreignTable.isNull()) + ui->fkTableCombo->setCurrentText(constr->foreignKey->foreignTable); + + // Conditions + foreach (SqliteForeignKey::Condition* condition, constr->foreignKey->conditions) + readCondition(condition); + + // Initially, Deferrable + ui->deferrableCombo->setCurrentText(sqliteDeferrable(constr->foreignKey->deferrable)); + ui->initiallyCombo->setCurrentText(sqliteInitially(constr->foreignKey->initially)); + + // Name + if (!constr->name.isNull()) + { + ui->namedCheckBox->setChecked(true); + ui->nameEdit->setText(constr->name); + } + + // Column + if (constr->foreignKey->indexedColumns.size() > 1) + { + qWarning() << "More than one referenced column in the column foreign key:" << constr->detokenize(); + return; + } + + QString fkColumn = column->name; + if (constr->foreignKey->indexedColumns.size() == 1) + fkColumn = constr->foreignKey->indexedColumns.first()->name; + + ui->fkColumnCombo->setCurrentText(fkColumn); +} + +void ColumnForeignKeyPanel::readCondition(SqliteForeignKey::Condition* condition) +{ + switch (condition->action) + { + case SqliteForeignKey::Condition::UPDATE: + ui->onUpdateCheckBox->setChecked(true); + ui->onUpdateCombo->setCurrentText(SqliteForeignKey::Condition::toString(condition->reaction)); + break; + case SqliteForeignKey::Condition::INSERT: + // INSERT is not officially supported. + break; + case SqliteForeignKey::Condition::DELETE: + ui->onDeleteCheckBox->setChecked(true); + ui->onDeleteCombo->setCurrentText(SqliteForeignKey::Condition::toString(condition->reaction)); + break; + case SqliteForeignKey::Condition::MATCH: + ui->matchCheckBox->setChecked(true); + ui->matchCombo->setCurrentText(SqliteForeignKey::Condition::toString(condition->reaction)); + break; + } +} + +void ColumnForeignKeyPanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + // Type + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::FOREIGN_KEY; + + // Cleanup & initial setup + if (constr->foreignKey) + delete constr->foreignKey; + + constr->foreignKey = new SqliteForeignKey(); + constr->foreignKey->setParent(constr); + + // Foreign table + constr->foreignKey->foreignTable = ui->fkTableCombo->currentText(); + + // Column + SqliteIndexedColumn* idxCol = new SqliteIndexedColumn(ui->fkColumnCombo->currentText()); + idxCol->setParent(constr->foreignKey); + constr->foreignKey->indexedColumns << idxCol; + + // Actions/reactions + if (ui->onDeleteCheckBox->isChecked()) + storeCondition(SqliteForeignKey::Condition::DELETE, ui->onDeleteCombo->currentText()); + + if (ui->onUpdateCheckBox->isChecked()) + storeCondition(SqliteForeignKey::Condition::UPDATE, ui->onDeleteCombo->currentText()); + + if (ui->matchCheckBox->isChecked()) + storeMatchCondition(ui->matchCombo->currentText()); + + // Deferred/initially + constr->foreignKey->deferrable = sqliteDeferrable(ui->deferrableCombo->currentText()); + constr->foreignKey->initially = sqliteInitially(ui->initiallyCombo->currentText()); + + // Name + constr->name = QString::null; + if (ui->namedCheckBox->isChecked()) + constr->name = ui->nameEdit->text(); +} + +void ColumnForeignKeyPanel::storeCondition(SqliteForeignKey::Condition::Action action, const QString& reaction) +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + + SqliteForeignKey::Condition* condition = new SqliteForeignKey::Condition( + action, + SqliteForeignKey::Condition::toEnum(reaction) + ); + condition->setParent(constr->foreignKey); + constr->foreignKey->conditions << condition; +} + +void ColumnForeignKeyPanel::storeMatchCondition(const QString& reaction) +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + + SqliteForeignKey::Condition* condition = new SqliteForeignKey::Condition(reaction); + condition->setParent(constr->foreignKey); + constr->foreignKey->conditions << condition; +} + +void ColumnForeignKeyPanel::readTables() +{ + SchemaResolver resolver(db); + resolver.setIgnoreSystemObjects(true); + QStringList tables = resolver.getTables(); // TODO named db attach not supported + + tables.sort(Qt::CaseInsensitive); + + ui->fkTableCombo->addItems(tables); + ui->fkTableCombo->setCurrentIndex(-1); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.h new file mode 100644 index 0000000..3fe3077 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.h @@ -0,0 +1,48 @@ +#ifndef COLUMNFOREIGNKEYPANEL_H +#define COLUMNFOREIGNKEYPANEL_H + +#include "constraintpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "guiSQLiteStudio_global.h" +#include <QStringListModel> +#include <QWidget> + +namespace Ui { + class ColumnForeignKeyPanel; +} + +class QGridLayout; +class QSignalMapper; + +class GUI_API_EXPORT ColumnForeignKeyPanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit ColumnForeignKeyPanel(QWidget *parent = 0); + ~ColumnForeignKeyPanel(); + + bool validate(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + + private: + void init(); + void readConstraint(); + void readTables(); + void readCondition(SqliteForeignKey::Condition* condition); + void storeCondition(SqliteForeignKey::Condition::Action action, const QString& reaction); + void storeMatchCondition(const QString& reaction); + + Ui::ColumnForeignKeyPanel *ui = nullptr; + QStringListModel fkColumnsModel; + + private slots: + void updateState(); + void updateFkColumns(); +}; + +#endif // COLUMNFOREIGNKEYPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.ui new file mode 100644 index 0000000..c442967 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.ui @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ColumnForeignKeyPanel</class> + <widget class="QWidget" name="ColumnForeignKeyPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>320</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>320</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="fkTableWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="fkTableLabel"> + <property name="text"> + <string>Foreign table:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="fkTableCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="fkColumnWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="fkColumnLabel"> + <property name="text"> + <string>Foreign column:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="fkColumnCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="reactionsGroup"> + <property name="title"> + <string>Reactions</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QCheckBox" name="onUpdateCheckBox"> + <property name="text"> + <string>ON UPDATE</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="onUpdateCombo"/> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="onDeleteCheckBox"> + <property name="text"> + <string>ON DELETE</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="matchCheckBox"> + <property name="text"> + <string>MATCH</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="onDeleteCombo"/> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="matchCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="deferredGroup"> + <property name="title"> + <string>Deferred foreign key</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QComboBox" name="deferrableCombo"/> + </item> + <item> + <widget class="QComboBox" name="initiallyCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QCheckBox" name="namedCheckBox"> + <property name="text"> + <string>Named constraint</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="nameEdit"> + <property name="placeholderText"> + <string>Constraint name</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>fkTableCombo</tabstop> + <tabstop>fkColumnCombo</tabstop> + <tabstop>onUpdateCheckBox</tabstop> + <tabstop>onUpdateCombo</tabstop> + <tabstop>onDeleteCheckBox</tabstop> + <tabstop>onDeleteCombo</tabstop> + <tabstop>matchCheckBox</tabstop> + <tabstop>matchCombo</tabstop> + <tabstop>deferrableCombo</tabstop> + <tabstop>initiallyCombo</tabstop> + <tabstop>namedCheckBox</tabstop> + <tabstop>nameEdit</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnnotnullpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnnotnullpanel.cpp new file mode 100644 index 0000000..9da20db --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnnotnullpanel.cpp @@ -0,0 +1,13 @@ +#include "columnnotnullpanel.h" +#include "parser/ast/sqlitecreatetable.h" + +ColumnNotNullPanel::ColumnNotNullPanel(QWidget *parent) : + ColumnUniqueAndNotNullPanel(parent) +{ +} + +void ColumnNotNullPanel::storeType() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::UNIQUE; +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnnotnullpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columnnotnullpanel.h new file mode 100644 index 0000000..1cde833 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnnotnullpanel.h @@ -0,0 +1,17 @@ +#ifndef COLUMNNOTNULLPANEL_H +#define COLUMNNOTNULLPANEL_H + +#include "guiSQLiteStudio_global.h" +#include "columnuniqueandnotnullpanel.h" + +class GUI_API_EXPORT ColumnNotNullPanel : public ColumnUniqueAndNotNullPanel +{ + Q_OBJECT + public: + explicit ColumnNotNullPanel(QWidget *parent = 0); + + protected: + void storeType(); +}; + +#endif // COLUMNNOTNULLPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp new file mode 100644 index 0000000..d10b223 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp @@ -0,0 +1,127 @@ +#include "columnprimarykeypanel.h" +#include "ui_columnprimarykeypanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "parser/keywords.h" +#include "datatype.h" +#include "uiutils.h" + +ColumnPrimaryKeyPanel::ColumnPrimaryKeyPanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::ColumnPrimaryKeyPanel) +{ + ui->setupUi(this); + init(); +} + +ColumnPrimaryKeyPanel::~ColumnPrimaryKeyPanel() +{ + delete ui; +} + +void ColumnPrimaryKeyPanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void ColumnPrimaryKeyPanel::init() +{ + QStringList sortOrders = {sqliteSortOrder(SqliteSortOrder::ASC), sqliteSortOrder(SqliteSortOrder::DESC)}; + ui->sortOrderCombo->addItems(sortOrders); + + ui->conflictCombo->addItems(getConflictAlgorithms()); + + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->sortOrderCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->conflictCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + updateState(); +} + +void ColumnPrimaryKeyPanel::readConstraint() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + if (constraint->dialect == Dialect::Sqlite3) + ui->autoIncrCheck->setChecked(constr->autoincrKw); + + if (constr->sortOrder != SqliteSortOrder::null) + { + ui->sortOrderCheck->setChecked(true); + ui->sortOrderCombo->setCurrentText(sqliteSortOrder(constr->sortOrder)); + } + + if (!constr->name.isNull()) + { + ui->namedCheck->setEnabled(true); + ui->namedEdit->setText(constr->name); + } + + if (constr->onConflict != SqliteConflictAlgo::null) + { + ui->conflictCheck->setChecked(true); + ui->conflictCombo->setCurrentText(sqliteConflictAlgo(constr->onConflict)); + } +} + +void ColumnPrimaryKeyPanel::updateState() +{ + ui->sortOrderCombo->setEnabled(ui->sortOrderCheck->isChecked()); + ui->namedEdit->setEnabled(ui->namedCheck->isChecked()); + ui->conflictCombo->setEnabled(ui->conflictCheck->isChecked()); +} + + +bool ColumnPrimaryKeyPanel::validate() +{ + bool nameOk = true; + if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty()) + nameOk = false; + + setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint.")); + + return nameOk; +} + +void ColumnPrimaryKeyPanel::constraintAvailable() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Column* column = dynamic_cast<SqliteCreateTable::Column*>(constraint->parent()); + ui->autoIncrCheck->setVisible(constraint->dialect == Dialect::Sqlite3); + ui->autoIncrCheck->setEnabled(column->type && + DataType::fromString(column->type->detokenize().trimmed(), Qt::CaseInsensitive) == DataType::INTEGER); + + if (!ui->autoIncrCheck->isEnabled()) + ui->autoIncrCheck->setText(tr("Autoincrement (only for %1 type columns)", "column primary key").arg("INTEGER")); + + readConstraint(); +} + +void ColumnPrimaryKeyPanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::PRIMARY_KEY; + + if (constraint->dialect == Dialect::Sqlite3) + constr->autoincrKw = ui->autoIncrCheck->isChecked(); + + if (ui->sortOrderCheck->isChecked() && ui->sortOrderCombo->currentIndex() > -1) + constr->sortOrder = sqliteSortOrder(ui->sortOrderCombo->currentText()); + + if (ui->namedCheck->isChecked()) + constr->name = ui->namedEdit->text(); + + if (ui->conflictCheck->isChecked() && ui->conflictCombo->currentIndex() > -1) + constr->onConflict = sqliteConflictAlgo(ui->conflictCombo->currentText()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.h new file mode 100644 index 0000000..ac97363 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.h @@ -0,0 +1,36 @@ +#ifndef COLUMNPRIMARYKEYPANEL_H +#define COLUMNPRIMARYKEYPANEL_H + +#include "constraintpanel.h" +#include "guiSQLiteStudio_global.h" + +namespace Ui { + class ColumnPrimaryKeyPanel; +} + +class GUI_API_EXPORT ColumnPrimaryKeyPanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit ColumnPrimaryKeyPanel(QWidget *parent = 0); + ~ColumnPrimaryKeyPanel(); + + bool validate(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + + private: + void init(); + void readConstraint(); + + Ui::ColumnPrimaryKeyPanel *ui = nullptr; + + private slots: + void updateState(); +}; + +#endif // COLUMNPRIMARYKEYPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.ui new file mode 100644 index 0000000..bedabca --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.ui @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ColumnPrimaryKeyPanel</class> + <widget class="QWidget" name="ColumnPrimaryKeyPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>379</width> + <height>110</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>110</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="autoIncrCheck"> + <property name="text"> + <string>Autoincrement</string> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="sortOrderWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="sortOrderCheck"> + <property name="text"> + <string>Sort order:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="sortOrderCombo"> + <property name="maximumSize"> + <size> + <width>80</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="namedCheck"> + <property name="text"> + <string>Named constraint:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="conflictWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="conflictCheck"> + <property name="text"> + <string>On conflict:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="conflictCombo"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp new file mode 100644 index 0000000..7c0f5a8 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp @@ -0,0 +1,99 @@ +#include "columnuniqueandnotnullpanel.h" +#include "ui_columnuniqueandnotnullpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "parser/keywords.h" +#include "uiutils.h" + +ColumnUniqueAndNotNullPanel::ColumnUniqueAndNotNullPanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::ColumnUniqueAndNotNullPanel) +{ + ui->setupUi(this); + init(); +} + +ColumnUniqueAndNotNullPanel::~ColumnUniqueAndNotNullPanel() +{ + delete ui; +} + +void ColumnUniqueAndNotNullPanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void ColumnUniqueAndNotNullPanel::init() +{ + ui->conflictCombo->addItems(getConflictAlgorithms()); + + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->conflictCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + updateState(); +} + +void ColumnUniqueAndNotNullPanel::readConstraint() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + + if (!constr->name.isNull()) + { + ui->namedCheck->setChecked(true); + ui->namedEdit->setText(constr->name); + } + + if (constr->onConflict != SqliteConflictAlgo::null) + { + ui->conflictCheck->setChecked(true); + ui->conflictCombo->setCurrentText(sqliteConflictAlgo(constr->onConflict)); + } +} + +void ColumnUniqueAndNotNullPanel::updateState() +{ + ui->namedEdit->setEnabled(ui->namedCheck->isChecked()); + ui->conflictCombo->setEnabled(ui->conflictCheck->isChecked()); +} + + +bool ColumnUniqueAndNotNullPanel::validate() +{ + bool nameOk = true; + if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty()) + nameOk = false; + + setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint.")); + + return nameOk; +} + +void ColumnUniqueAndNotNullPanel::constraintAvailable() +{ + if (constraint.isNull()) + return; + + readConstraint(); +} + +void ColumnUniqueAndNotNullPanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + storeType(); + + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + if (ui->namedCheck->isChecked()) + constr->name = ui->namedEdit->text(); + + if (ui->conflictCheck->isChecked() && ui->conflictCombo->currentIndex() > -1) + constr->onConflict = sqliteConflictAlgo(ui->conflictCombo->currentText()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.h new file mode 100644 index 0000000..95cd5fb --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.h @@ -0,0 +1,37 @@ +#ifndef COLUMNUNIQUEANDNOTNULLPANEL_H +#define COLUMNUNIQUEANDNOTNULLPANEL_H + +#include "constraintpanel.h" +#include "guiSQLiteStudio_global.h" + +namespace Ui { + class ColumnUniqueAndNotNullPanel; +} + +class GUI_API_EXPORT ColumnUniqueAndNotNullPanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit ColumnUniqueAndNotNullPanel(QWidget *parent = 0); + ~ColumnUniqueAndNotNullPanel(); + + bool validate(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + virtual void storeType() = 0; + + private: + void init(); + void readConstraint(); + + Ui::ColumnUniqueAndNotNullPanel *ui = nullptr; + + private slots: + void updateState(); +}; + +#endif // COLUMNUNIQUEANDNOTNULLPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.ui new file mode 100644 index 0000000..16efc89 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.ui @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ColumnUniqueAndNotNullPanel</class> + <widget class="QWidget" name="ColumnUniqueAndNotNullPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>82</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>80</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="namedCheck"> + <property name="text"> + <string>Named constraint:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="conflictWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="conflictCheck"> + <property name="text"> + <string>On conflict:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="conflictCombo"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniquepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniquepanel.cpp new file mode 100644 index 0000000..da5e00b --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniquepanel.cpp @@ -0,0 +1,13 @@ +#include "columnuniquepanel.h" +#include "parser/ast/sqlitecreatetable.h" + +ColumnUniquePanel::ColumnUniquePanel(QWidget *parent) : + ColumnUniqueAndNotNullPanel(parent) +{ +} + +void ColumnUniquePanel::storeType() +{ + SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Column::Constraint::UNIQUE; +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniquepanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniquepanel.h new file mode 100644 index 0000000..3abf779 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniquepanel.h @@ -0,0 +1,22 @@ +#ifndef COLUMNUNIQUEPANEL_H +#define COLUMNUNIQUEPANEL_H + +#include "columnuniqueandnotnullpanel.h" +#include "guiSQLiteStudio_global.h" + +namespace Ui { + class ColumnUniquePanel; +} + +class GUI_API_EXPORT ColumnUniquePanel : public ColumnUniqueAndNotNullPanel +{ + Q_OBJECT + + public: + explicit ColumnUniquePanel(QWidget *parent = 0); + + protected: + void storeType(); +}; + +#endif // COLUMNUNIQUEPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp new file mode 100644 index 0000000..adb5e2b --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp @@ -0,0 +1,175 @@ +#include "constraintcheckpanel.h" +#include "ui_constraintcheckpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "parser/parser.h" +#include "parser/keywords.h" +#include "uiutils.h" +#include <QDebug> + +ConstraintCheckPanel::ConstraintCheckPanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::ConstraintCheckPanel) +{ + ui->setupUi(this); + init(); +} + +ConstraintCheckPanel::~ConstraintCheckPanel() +{ + delete ui; +} + +void ConstraintCheckPanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + + +bool ConstraintCheckPanel::validate() +{ + bool nameOk = true; + if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty()) + nameOk = false; + + bool exprOk = !ui->exprEdit->toPlainText().trimmed().isEmpty() && + !ui->exprEdit->haveErrors(); + + bool exprCheckedOk = exprOk && ui->exprEdit->isSyntaxChecked(); + + setValidState(ui->exprEdit, exprOk, tr("Enter a valid condition.")); + setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint.")); + + return exprCheckedOk && nameOk; +} + +void ConstraintCheckPanel::constraintAvailable() +{ + if (constraint.isNull()) + return; + + if (constraint->dialect == Dialect::Sqlite3) + { + ui->onConflictCheck->setVisible(false); + ui->onConflictCombo->setVisible(false); + } + + readConstraint(); + updateVirtualSql(); +} + +void ConstraintCheckPanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + storeType(); + + SqliteExprPtr expr = parseExpression(ui->exprEdit->toPlainText()); + SqliteExpr* newExpr = new SqliteExpr(*expr.data()); + newExpr->setParent(constraint.data()); + storeExpr(newExpr); + + QString name = QString::null; + if (ui->namedCheck->isChecked()) + name = ui->namedEdit->text(); + + storeName(name); + + if (constraint->dialect == Dialect::Sqlite2 && ui->onConflictCheck->isChecked()) + storeConflictAlgo(sqliteConflictAlgo(ui->onConflictCombo->currentText())); +} + +void ConstraintCheckPanel::init() +{ + setFocusProxy(ui->exprEdit); + ui->exprEdit->setShowLineNumbers(false); + + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->exprEdit, SIGNAL(textChanged()), this, SIGNAL(updateValidation())); + connect(ui->exprEdit, SIGNAL(errorsChecked(bool)), this, SIGNAL(updateValidation())); + + connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->onConflictCheck, SIGNAL(toggled(bool)), this, SLOT(updateState())); + + ui->onConflictCombo->addItems(getConflictAlgorithms()); + + updateState(); +} + +void ConstraintCheckPanel::readConstraint() +{ + SqliteExpr* expr = readExpr(); + if (expr) + ui->exprEdit->setPlainText(expr->detokenize()); + + QString name = readName(); + if (!name.isNull()) + { + ui->namedCheck->setChecked(true); + ui->namedEdit->setText(name); + } + + SqliteConflictAlgo onConflict = readConflictAlgo(); + if (constraint->dialect == Dialect::Sqlite2 && onConflict != SqliteConflictAlgo::null) + { + ui->onConflictCheck->setChecked(true); + ui->onConflictCombo->setCurrentText(sqliteConflictAlgo(onConflict)); + } +} + +void ConstraintCheckPanel::updateVirtualSql() +{ + ui->exprEdit->setDb(db); + + SqliteCreateTable* createTable = getCreateTable(); + + createTable->rebuildTokens(); + TokenList tokens = createTable->tokens; + int idx = tokens.lastIndexOf(Token::PAR_RIGHT); + if (idx == -1) + { + qWarning() << "CREATE TABLE tokens are invalid while call to ConstraintCheckPanel::updateVirtualSql()."; + return; + } + + TokenList newTokens; + newTokens << TokenPtr::create(Token::OPERATOR, ",") + << TokenPtr::create(Token::SPACE, " ") + << TokenPtr::create(Token::KEYWORD, "CHECK") + << TokenPtr::create(Token::SPACE, " ") + << TokenPtr::create(Token::PAR_LEFT, "(") + << TokenPtr::create(Token::OTHER, "%1") + << TokenPtr::create(Token::PAR_RIGHT, ")"); + + tokens.insert(idx, newTokens); + QString sql = tokens.detokenize(); + + ui->exprEdit->setVirtualSqlExpression(sql); +} + +SqliteExprPtr ConstraintCheckPanel::parseExpression(const QString& sql) +{ + Parser parser(db->getDialect()); + SqliteExpr *expr = parser.parseExpr(sql); + return SqliteExprPtr(expr); +} + +void ConstraintCheckPanel::updateState() +{ + ui->namedEdit->setEnabled(ui->namedCheck->isChecked()); + ui->onConflictCombo->setEnabled(ui->onConflictCheck->isChecked()); +} + +bool ConstraintCheckPanel::validateOnly() +{ + ui->exprEdit->checkSyntaxNow(); + return validate(); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.h new file mode 100644 index 0000000..5098880 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.h @@ -0,0 +1,49 @@ +#ifndef CONSTRAINTCHECKPANEL_H +#define CONSTRAINTCHECKPANEL_H + +#include "constraintpanel.h" +#include "parser/ast/sqliteconflictalgo.h" +#include "guiSQLiteStudio_global.h" +#include <QWidget> + +namespace Ui { + class ConstraintCheckPanel; +} + +class GUI_API_EXPORT ConstraintCheckPanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit ConstraintCheckPanel(QWidget *parent = 0); + ~ConstraintCheckPanel(); + + bool validate(); + bool validateOnly(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + virtual SqliteExpr* readExpr() = 0; + virtual QString readName() = 0; + virtual void storeType() = 0; + virtual SqliteConflictAlgo readConflictAlgo() = 0; + virtual void storeExpr(SqliteExpr* expr) = 0; + virtual void storeName(const QString& name) = 0; + virtual void storeConflictAlgo(SqliteConflictAlgo algo) = 0; + virtual SqliteCreateTable* getCreateTable() = 0; + + private: + void init(); + void readConstraint(); + void updateVirtualSql(); + SqliteExprPtr parseExpression(const QString& sql); + + Ui::ConstraintCheckPanel *ui = nullptr; + + private slots: + void updateState(); +}; + +#endif // CONSTRAINTCHECKPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.ui new file mode 100644 index 0000000..58f58e6 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.ui @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConstraintCheckPanel</class> + <widget class="QWidget" name="ConstraintCheckPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>197</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="exprGroup"> + <property name="title"> + <string>The expression</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="SqlEditor" name="exprEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QCheckBox" name="namedCheck"> + <property name="text"> + <string>Named constraint:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="onConflictWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QCheckBox" name="onConflictCheck"> + <property name="text"> + <string>On conflict</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="onConflictCombo"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>SqlEditor</class> + <extends>QPlainTextEdit</extends> + <header>sqleditor.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp new file mode 100644 index 0000000..031fbfe --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp @@ -0,0 +1,96 @@ +#include "constraintpanel.h" +#include "common/unused.h" +#include "constraints/tableprimarykeypanel.h" +#include "constraints/tableforeignkeypanel.h" +#include "constraints/tableuniquepanel.h" +#include "constraints/tablecheckpanel.h" +#include "constraints/columncheckpanel.h" +#include "constraints/columncollatepanel.h" +#include "constraints/columndefaultpanel.h" +#include "constraints/columnforeignkeypanel.h" +#include "constraints/columnnotnullpanel.h" +#include "constraints/columnprimarykeypanel.h" +#include "constraints/columnuniquepanel.h" +#include <QDebug> + +ConstraintPanel::ConstraintPanel(QWidget *parent) : + QWidget(parent) +{ +} + +ConstraintPanel::~ConstraintPanel() +{ +} + +void ConstraintPanel::setConstraint(SqliteStatement* stmt) +{ + constraint = stmt; + constraintAvailable(); +} + +void ConstraintPanel::storeDefinition() +{ + storeConfiguration(); + constraint->rebuildTokens(); +} + +void ConstraintPanel::setDb(Db* value) +{ + db = value; +} + +bool ConstraintPanel::validateOnly() +{ + return validate(); +} + +ConstraintPanel* ConstraintPanel::produce(SqliteCreateTable::Constraint* constr) +{ + switch (constr->type) + { + case SqliteCreateTable::Constraint::PRIMARY_KEY: + return new TablePrimaryKeyPanel(); + case SqliteCreateTable::Constraint::UNIQUE: + return new TableUniquePanel(); + case SqliteCreateTable::Constraint::CHECK: + return new TableCheckPanel(); + case SqliteCreateTable::Constraint::FOREIGN_KEY: + return new TableForeignKeyPanel(); + case SqliteCreateTable::Constraint::NAME_ONLY: + break; + } + + qCritical() << "No panel defined in ConstraintPanel::createConstraintPanel()!"; + Q_ASSERT_X(true, "ConstraintPanel::produce()", "No panel defined!"); + return nullptr; +} + +ConstraintPanel* ConstraintPanel::produce(SqliteCreateTable::Column::Constraint* constr) +{ + switch (constr->type) + { + case SqliteCreateTable::Column::Constraint::PRIMARY_KEY: + return new ColumnPrimaryKeyPanel(); + case SqliteCreateTable::Column::Constraint::NOT_NULL: + return new ColumnNotNullPanel(); + case SqliteCreateTable::Column::Constraint::UNIQUE: + return new ColumnUniquePanel(); + case SqliteCreateTable::Column::Constraint::CHECK: + return new ColumnCheckPanel(); + case SqliteCreateTable::Column::Constraint::DEFAULT: + return new ColumnDefaultPanel(); + case SqliteCreateTable::Column::Constraint::COLLATE: + return new ColumnCollatePanel(); + case SqliteCreateTable::Column::Constraint::FOREIGN_KEY: + return new ColumnForeignKeyPanel(); + case SqliteCreateTable::Column::Constraint::NULL_: + case SqliteCreateTable::Column::Constraint::NAME_ONLY: + case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY: + break; + } + + qCritical() << "No panel defined in ConstraintPanel::createConstraintPanel()!"; + Q_ASSERT_X(true, "ConstraintPanel::produce()", "No panel defined"); + return nullptr; +} + diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h new file mode 100644 index 0000000..9f875a9 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h @@ -0,0 +1,79 @@ +#ifndef CONSTRAINTPANEL_H +#define CONSTRAINTPANEL_H + +#include "db/db.h" +#include "parser/ast/sqlitecreatetable.h" +#include "guiSQLiteStudio_global.h" +#include <QWidget> +#include <QPointer> + +class GUI_API_EXPORT ConstraintPanel : public QWidget +{ + Q_OBJECT + + public: + explicit ConstraintPanel(QWidget *parent = 0); + virtual ~ConstraintPanel(); + + void setConstraint(SqliteStatement* stmt); + void storeDefinition(); + virtual void setDb(Db* value); + + /** + * @brief validate Validates panel for correct data filled in. + * @return true if the data is valid, or false otherwise. + * Apart from returning boolean result it also marks + * invalid fields with red color. See validateOnly() description + * for details on differences between those two methods. + */ + virtual bool validate() = 0; + + /** + * @brief validateOnly Validates panel for correct data filled in. + * @return true if the data is valid, or false otherwise. + * The difference between validateOnly() and validate() is that validateOnly() + * will run all validations immediately (ie. SQL syntax checking + * in DEFAULT constraint, etc), while the validate() will wait for + * SqlEditor to do the validation in its scheduled time and return + * false until the validation isn't done yet. + * The validate() should be used when user actually edits the panel, + * while validateOnly() is to be used when using ConstraintPanel for validation + * of a Constraint object, but not displayed - in that case the validation + * result is needed immediately and that's where validateOnly() does its job. + * Not every constraint panel has to reimplement this. Most of the constraints + * don't work asynchronously and return proper result just from a validate() call. + * In that case the default implementation of validateOnly() will do the job. + */ + virtual bool validateOnly(); + + static ConstraintPanel* produce(SqliteCreateTable::Constraint* constr); + static ConstraintPanel* produce(SqliteCreateTable::Column::Constraint* constr); + + protected: + /** + * @brief constraintAvailable + * This method is called once the constraint object (the member variable) + * is available to the panel as well, as the database (the db member). + * The implementation should read values from constraint object and put them + * to panel's fields, but also initialise any database related data, + * like existing collations, etc. + */ + virtual void constraintAvailable() = 0; + + /** + * @brief storeConfiguration + * The implementation should store all field valies into the constraint object. + */ + virtual void storeConfiguration() = 0; + + Db* db = nullptr; + QPointer<SqliteStatement> constraint; + + public slots: + + signals: + void updateValidation(); + +}; + +#endif // CONSTRAINTPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablecheckpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tablecheckpanel.cpp new file mode 100644 index 0000000..72c9d35 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablecheckpanel.cpp @@ -0,0 +1,56 @@ +#include "tablecheckpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "parser/parser.h" +#include <QDebug> + +TableCheckPanel::TableCheckPanel(QWidget *parent) : + ConstraintCheckPanel(parent) +{ +} + +SqliteExpr* TableCheckPanel::readExpr() +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + return constr->expr; +} + +QString TableCheckPanel::readName() +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + return constr->name; +} + +void TableCheckPanel::storeType() +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Constraint::CHECK; +} + +SqliteConflictAlgo TableCheckPanel::readConflictAlgo() +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + return constr->onConflict; +} + +void TableCheckPanel::storeExpr(SqliteExpr* expr) +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->expr = expr; +} + +void TableCheckPanel::storeName(const QString& name) +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->name = name; +} + +void TableCheckPanel::storeConflictAlgo(SqliteConflictAlgo algo) +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->onConflict = algo; +} + +SqliteCreateTable* TableCheckPanel::getCreateTable() +{ + return dynamic_cast<SqliteCreateTable*>(constraint->parentStatement()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablecheckpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/tablecheckpanel.h new file mode 100644 index 0000000..af9039e --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablecheckpanel.h @@ -0,0 +1,27 @@ +#ifndef TABLECHECKPANEL_H +#define TABLECHECKPANEL_H + +#include "constraintcheckpanel.h" +#include "constraintpanel.h" +#include "guiSQLiteStudio_global.h" +#include <QWidget> + +class GUI_API_EXPORT TableCheckPanel : public ConstraintCheckPanel +{ + Q_OBJECT + + public: + explicit TableCheckPanel(QWidget *parent = 0); + + protected: + SqliteExpr* readExpr(); + QString readName(); + void storeType(); + SqliteConflictAlgo readConflictAlgo(); + void storeExpr(SqliteExpr* expr); + void storeName(const QString& name); + void storeConflictAlgo(SqliteConflictAlgo algo); + SqliteCreateTable* getCreateTable(); +}; + +#endif // TABLECHECKPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp new file mode 100644 index 0000000..60da220 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp @@ -0,0 +1,418 @@ +#include "tableforeignkeypanel.h" +#include "ui_tableforeignkeypanel.h" +#include "schemaresolver.h" +#include "uiutils.h" +#include "common/widgetstateindicator.h" +#include <QDebug> +#include <QSignalMapper> + +TableForeignKeyPanel::TableForeignKeyPanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::TableForeignKeyPanel) +{ + ui->setupUi(this); + init(); +} + +TableForeignKeyPanel::~TableForeignKeyPanel() +{ + delete ui; +} + +void TableForeignKeyPanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + + +bool TableForeignKeyPanel::validate() +{ + bool tableOk = (ui->fkTableCombo->currentIndex() > -1); + + bool columnsOk = false; + bool columnsSelected = true; + bool idxOk = true; + QCheckBox* check = nullptr; + QComboBox* combo = nullptr; + for (int i = 0; i < totalColumns; i++) + { + check = qobject_cast<QCheckBox*>(columnsLayout->itemAtPosition(i, 0)->widget()); + combo = qobject_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget()); + if (check->isChecked()) + { + columnsOk = true; + + idxOk = (combo->currentIndex() > -1); + setValidState(combo, idxOk, tr("Pick the foreign column.")); + if (!idxOk) + columnsSelected = false; + + break; + } + } + + bool nameOk = true; + if (ui->namedCheckBox->isChecked() && ui->nameEdit->text().isEmpty()) + nameOk = false; + + setValidState(ui->fkTableCombo, tableOk, tr("Pick the foreign table.")); + setValidState(ui->columnsGroup, columnsOk, tr("Select at least one foreign column.")); + setValidState(ui->nameEdit, nameOk, tr("Enter a name of the constraint.")); + + return tableOk && columnsOk && nameOk && columnsSelected; +} + +void TableForeignKeyPanel::setDb(Db* value) +{ + ConstraintPanel::setDb(value); + ui->sqlite2Warn->setVisible(value->getDialect() == Dialect::Sqlite2); +} + +void TableForeignKeyPanel::constraintAvailable() +{ + readTables(); + buildColumns(); + readConstraint(); +} + +void TableForeignKeyPanel::init() +{ + setFocusProxy(ui->fkTableCombo); + columnsLayout = new QGridLayout(); + ui->columnsScrollContents->setLayout(columnsLayout); + + columnSignalMapping = new QSignalMapper(this); + connect(columnSignalMapping, SIGNAL(mapped(int)), this, SLOT(updateColumnState(int))); + + connect(ui->namedCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->nameEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + connect(ui->fkTableCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateValidation())); + connect(ui->fkTableCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFkColumns())); + connect(ui->fkTableCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateState())); + connect(ui->onDeleteCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->onUpdateCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->matchCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + + ui->deferrableCombo->addItems({ + "", + sqliteDeferrable(SqliteDeferrable::DEFERRABLE), + sqliteDeferrable(SqliteDeferrable::NOT_DEFERRABLE) + }); + ui->initiallyCombo->addItems({ + "", + sqliteInitially(SqliteInitially::DEFERRED), + sqliteInitially(SqliteInitially::IMMEDIATE), + }); + + QStringList reactions = { + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::NO_ACTION), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::SET_NULL), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::SET_DEFAULT), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::CASCADE), + SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::RESTRICT) + }; + ui->onUpdateCombo->addItems(reactions); + ui->onDeleteCombo->addItems(reactions); + ui->matchCombo->addItems({"SIMPLE", "FULL", "PARTIAL"}); + + connect(ui->namedCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + updateState(); +} + +void TableForeignKeyPanel::updateState() +{ + bool tableSelected = (ui->fkTableCombo->currentIndex() > -1); + for (int i = 0; i < totalColumns; i++) + updateColumnState(i, tableSelected); + + ui->deferrableCombo->setEnabled(tableSelected); + ui->initiallyCombo->setEnabled(tableSelected); + ui->namedCheckBox->setEnabled(tableSelected); + ui->nameEdit->setEnabled(tableSelected && ui->namedCheckBox->isChecked()); + ui->onDeleteCheckBox->setEnabled(tableSelected); + ui->onUpdateCheckBox->setEnabled(tableSelected); + ui->matchCheckBox->setEnabled(tableSelected); + ui->onDeleteCombo->setEnabled(tableSelected && ui->onDeleteCheckBox->isChecked()); + ui->onUpdateCombo->setEnabled(tableSelected && ui->onUpdateCheckBox->isChecked()); + ui->matchCombo->setEnabled(tableSelected && ui->matchCheckBox->isChecked()); +} + +void TableForeignKeyPanel::updateColumnState(int rowIdx, bool tableSelected) +{ + QCheckBox* check = qobject_cast<QCheckBox*>(columnsLayout->itemAtPosition(rowIdx, 0)->widget()); + bool wasEnabled = check->isEnabled(); + check->setEnabled(tableSelected); + + QComboBox* combo = qobject_cast<QComboBox*>(columnsLayout->itemAtPosition(rowIdx, 1)->widget()); + combo->setEnabled(tableSelected && check->isChecked()); + + if (!wasEnabled && check->isEnabled()) + { + // Automatically set matching column + int idx = fkColumnsModel.stringList().indexOf(check->text()); + if (idx > -1) + combo->setCurrentIndex(idx); + } +} + +void TableForeignKeyPanel::updateColumnState(int rowIdx) +{ + bool tableSelected = (ui->fkTableCombo->currentIndex() > -1); + updateColumnState(rowIdx, tableSelected); +} + +void TableForeignKeyPanel::updateFkColumns() +{ + QStringList columns; + if (ui->fkTableCombo->currentIndex() == -1) + { + fkColumnsModel.setStringList(columns); + updateState(); + return; + } + + SchemaResolver resolver(db); + columns = resolver.getTableColumns(ui->fkTableCombo->currentText()); // TODO named db attach not supported + fkColumnsModel.setStringList(columns); +} + +void TableForeignKeyPanel::buildColumns() +{ + totalColumns = 0; + if (constraint.isNull()) + return; + + SqliteCreateTable* createTable = dynamic_cast<SqliteCreateTable*>(constraint->parentStatement()); + int row = 0; + foreach (SqliteCreateTable::Column* column, createTable->columns) + buildColumn(column, row++); +} + +void TableForeignKeyPanel::buildColumn(SqliteCreateTable::Column* column, int row) +{ + int col = 0; + + QCheckBox* check = new QCheckBox(column->name); + columnsLayout->addWidget(check, row, col++); + columnSignalMapping->setMapping(check, row); + connect(check, SIGNAL(toggled(bool)), columnSignalMapping, SLOT(map())); + connect(check, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + + QComboBox* fkCol = new QComboBox(); + fkCol->setToolTip(tr("Foreign column", "table constraints")); + fkCol->setModel(&fkColumnsModel); + columnsLayout->addWidget(fkCol, row, col++); + connect(fkCol, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateValidation())); + + totalColumns++; + + updateColumnState(row); +} + +void TableForeignKeyPanel::readConstraint() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + if (!constr->foreignKey) + return; + + if (!constr->foreignKey->foreignTable.isNull()) + ui->fkTableCombo->setCurrentText(constr->foreignKey->foreignTable); + + foreach (SqliteForeignKey::Condition* condition, constr->foreignKey->conditions) + readCondition(condition); + + ui->deferrableCombo->setCurrentText(sqliteDeferrable(constr->foreignKey->deferrable)); + ui->initiallyCombo->setCurrentText(sqliteInitially(constr->foreignKey->initially)); + + // Name + if (!constr->name.isNull()) + { + ui->namedCheckBox->setChecked(true); + ui->nameEdit->setText(constr->name); + } + + // Columns + int idx; + QCheckBox* check = nullptr; + QComboBox* combo = nullptr; + SqliteIndexedColumn* localCol = nullptr; + SqliteIndexedColumn* foreignCol = nullptr; + int i = 0; + foreach (localCol, constr->indexedColumns) + { + // Foreign col + if (i < constr->foreignKey->indexedColumns.size()) + foreignCol = constr->foreignKey->indexedColumns[i]; + else + foreignCol = nullptr; + + i++; + + // Column index + idx = getColumnIndex(localCol->name); + if (idx < 0) + continue; + + // Column states + check = dynamic_cast<QCheckBox*>(columnsLayout->itemAtPosition(idx, 0)->widget()); + check->setChecked(true); + + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 1)->widget()); + if (foreignCol) + combo->setCurrentText(foreignCol->name); + else if (fkColumnsModel.stringList().contains(localCol->name)) + combo->setCurrentText(localCol->name); + else + combo->setCurrentIndex(-1); + } +} + +void TableForeignKeyPanel::readCondition(SqliteForeignKey::Condition* condition) +{ + switch (condition->action) + { + case SqliteForeignKey::Condition::UPDATE: + ui->onUpdateCheckBox->setChecked(true); + ui->onUpdateCombo->setCurrentText(SqliteForeignKey::Condition::toString(condition->reaction)); + break; + case SqliteForeignKey::Condition::INSERT: + // INSERT is not officially supported. + break; + case SqliteForeignKey::Condition::DELETE: + ui->onDeleteCheckBox->setChecked(true); + ui->onDeleteCombo->setCurrentText(SqliteForeignKey::Condition::toString(condition->reaction)); + break; + case SqliteForeignKey::Condition::MATCH: + ui->matchCheckBox->setChecked(true); + ui->matchCombo->setCurrentText(SqliteForeignKey::Condition::toString(condition->reaction)); + break; + } +} + +void TableForeignKeyPanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + // Type + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Constraint::FOREIGN_KEY; + + // Cleanup & initial setup + if (constr->foreignKey) + delete constr->foreignKey; + + foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + delete idxCol; + + constr->indexedColumns.clear(); + + constr->foreignKey = new SqliteForeignKey(); + constr->foreignKey->setParent(constr); + + // Foreign table + constr->foreignKey->foreignTable = ui->fkTableCombo->currentText(); + + // Columns + QCheckBox* check = nullptr; + QComboBox* combo = nullptr; + SqliteIndexedColumn* idxCol = nullptr; + QString name; + for (int i = 0; i < totalColumns; i++) + { + // Local column + check = dynamic_cast<QCheckBox*>(columnsLayout->itemAtPosition(i, 0)->widget()); + if (!check->isChecked()) + continue; + + idxCol = new SqliteIndexedColumn(check->text()); + idxCol->setParent(constr); + constr->indexedColumns << idxCol; + + // Foreign column + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget()); + + idxCol = new SqliteIndexedColumn(combo->currentText()); + idxCol->setParent(constr->foreignKey); + constr->foreignKey->indexedColumns << idxCol; + } + + // Actions/reactions + if (ui->onDeleteCheckBox->isChecked()) + storeCondition(SqliteForeignKey::Condition::DELETE, ui->onDeleteCombo->currentText()); + + if (ui->onUpdateCheckBox->isChecked()) + storeCondition(SqliteForeignKey::Condition::UPDATE, ui->onDeleteCombo->currentText()); + + if (ui->matchCheckBox->isChecked()) + storeMatchCondition(ui->matchCombo->currentText()); + + // Deferred/initially + constr->foreignKey->deferrable = sqliteDeferrable(ui->deferrableCombo->currentText()); + constr->foreignKey->initially = sqliteInitially(ui->initiallyCombo->currentText()); + + // Name + constr->name = QString::null; + if (ui->namedCheckBox->isChecked()) + constr->name = ui->nameEdit->text(); +} + +void TableForeignKeyPanel::storeCondition(SqliteForeignKey::Condition::Action action, const QString& reaction) +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + + SqliteForeignKey::Condition* condition = new SqliteForeignKey::Condition( + action, + SqliteForeignKey::Condition::toEnum(reaction) + ); + condition->setParent(constr->foreignKey); + constr->foreignKey->conditions << condition; +} + +void TableForeignKeyPanel::storeMatchCondition(const QString& reaction) +{ + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + + SqliteForeignKey::Condition* condition = new SqliteForeignKey::Condition(reaction); + condition->setParent(constr->foreignKey); + constr->foreignKey->conditions << condition; +} + +void TableForeignKeyPanel::readTables() +{ + SchemaResolver resolver(db); + resolver.setIgnoreSystemObjects(true); + QStringList tables = resolver.getTables(); // TODO named db attach not supported + + SqliteCreateTable* createTable = dynamic_cast<SqliteCreateTable*>(constraint->parentStatement()); + tables.removeOne(createTable->table); + + tables.sort(Qt::CaseInsensitive); + + ui->fkTableCombo->addItems(tables); + ui->fkTableCombo->setCurrentIndex(-1); +} + +int TableForeignKeyPanel::getColumnIndex(const QString& colName) +{ + QWidget* item = nullptr; + QCheckBox* cb = nullptr; + for (int i = 0; i < totalColumns; i++) + { + item = columnsLayout->itemAtPosition(i, 0)->widget(); + cb = qobject_cast<QCheckBox*>(item); + if (cb->text().compare(colName, Qt::CaseInsensitive) == 0) + return i; + } + return -1; +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h new file mode 100644 index 0000000..cecc04a --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h @@ -0,0 +1,57 @@ +#ifndef TABLEFOREIGNKEYPANEL_H +#define TABLEFOREIGNKEYPANEL_H + +#include "constraintpanel.h" +#include "parser/ast/sqlitecreatetable.h" +#include "guiSQLiteStudio_global.h" +#include <QStringListModel> +#include <QWidget> + +namespace Ui { + class TableForeignKeyPanel; +} + +class QGridLayout; +class QSignalMapper; + +class GUI_API_EXPORT TableForeignKeyPanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit TableForeignKeyPanel(QWidget *parent = 0); + ~TableForeignKeyPanel(); + + bool validate(); + void setDb(Db* value); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + void storeConfiguration(); + + private: + void init(); + void buildColumns(); + void buildColumn(SqliteCreateTable::Column* column, int row); + void readConstraint(); + void readTables(); + void readCondition(SqliteForeignKey::Condition* condition); + int getColumnIndex(const QString& colName); + void storeCondition(SqliteForeignKey::Condition::Action action, const QString& reaction); + void storeMatchCondition(const QString& reaction); + + Ui::TableForeignKeyPanel *ui = nullptr; + QGridLayout* columnsLayout = nullptr; + int totalColumns = 0; + QStringListModel fkColumnsModel; + QSignalMapper* columnSignalMapping = nullptr; + + private slots: + void updateState(); + void updateColumnState(int rowIdx, bool tableSelected); + void updateColumnState(int rowIdx); + void updateFkColumns(); +}; + +#endif // TABLEFOREIGNKEYPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui new file mode 100644 index 0000000..8917381 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TableForeignKeyPanel</class> + <widget class="QWidget" name="TableForeignKeyPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>400</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>400</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="fkTableWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="fkTableLabel"> + <property name="text"> + <string>Foreign table:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="fkTableCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QLabel" name="sqlite2Warn"> + <property name="font"> + <font> + <pointsize>8</pointsize> + <italic>true</italic> + </font> + </property> + <property name="text"> + <string>SQLite 2 does not support foreign keys officially, +but it's okay to use them anyway.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="columnsGroup"> + <property name="title"> + <string>Columns</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QWidget" name="columnsHeader" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="colHdrLocal"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Local column</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="colHdrForeign"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Foreign column</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QScrollArea" name="columnsArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="columnsScrollContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>362</width> + <height>25</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="reactionsGroup"> + <property name="title"> + <string>Reactions</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QCheckBox" name="onUpdateCheckBox"> + <property name="text"> + <string>ON UPDATE</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="onUpdateCombo"/> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="onDeleteCheckBox"> + <property name="text"> + <string>ON DELETE</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="matchCheckBox"> + <property name="text"> + <string>MATCH</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="onDeleteCombo"/> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="matchCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="deferredGroup"> + <property name="title"> + <string>Deferred foreign key</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QComboBox" name="deferrableCombo"/> + </item> + <item> + <widget class="QComboBox" name="initiallyCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QCheckBox" name="namedCheckBox"> + <property name="text"> + <string>Named constraint</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="nameEdit"> + <property name="placeholderText"> + <string>Constraint name</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>fkTableCombo</tabstop> + <tabstop>columnsArea</tabstop> + <tabstop>onUpdateCheckBox</tabstop> + <tabstop>onUpdateCombo</tabstop> + <tabstop>onDeleteCheckBox</tabstop> + <tabstop>onDeleteCombo</tabstop> + <tabstop>matchCheckBox</tabstop> + <tabstop>matchCombo</tabstop> + <tabstop>deferrableCombo</tabstop> + <tabstop>initiallyCombo</tabstop> + <tabstop>namedCheckBox</tabstop> + <tabstop>nameEdit</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp new file mode 100644 index 0000000..f2a0ada --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp @@ -0,0 +1,299 @@ +#include "tablepkanduniquepanel.h" +#include "ui_tablepkanduniquepanel.h" +#include "parser/keywords.h" +#include "schemaresolver.h" +#include "uiutils.h" +#include <QGridLayout> +#include <QHBoxLayout> +#include <QCheckBox> +#include <QComboBox> +#include <QLabel> +#include <QSignalMapper> +#include <QDebug> +#include <QScrollBar> + +TablePrimaryKeyAndUniquePanel::TablePrimaryKeyAndUniquePanel(QWidget *parent) : + ConstraintPanel(parent), + ui(new Ui::TablePrimaryKeyAndUniquePanel) +{ + ui->setupUi(this); + init(); +} + +TablePrimaryKeyAndUniquePanel::~TablePrimaryKeyAndUniquePanel() +{ + delete ui; +} + +void TablePrimaryKeyAndUniquePanel::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void TablePrimaryKeyAndUniquePanel::init() +{ + columnsLayout = new QGridLayout(); + ui->scrollAreaWidgetContents->setLayout(columnsLayout); + + connect(ui->namedCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + connect(ui->namedLineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation())); + + ui->conflictComboBox->addItems(getConflictAlgorithms()); + + columnSignalMapping = new QSignalMapper(this); + connect(columnSignalMapping, SIGNAL(mapped(int)), this, SLOT(updateColumnState(int))); + + connect(ui->namedCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + connect(ui->conflictCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateState())); + updateState(); +} + +void TablePrimaryKeyAndUniquePanel::readCollations() +{ + SchemaResolver resolver(db); + QStringList collList = resolver.getCollations(); + + if (collList.size() > 0) + collList.prepend(""); + + collations.setStringList(collList); +} + +void TablePrimaryKeyAndUniquePanel::buildColumn(SqliteCreateTable::Column* column, int row) +{ + int col = 0; + + QCheckBox* check = new QCheckBox(column->name); + columnsLayout->addWidget(check, row, col++); + columnSignalMapping->setMapping(check, row); + connect(check, SIGNAL(toggled(bool)), columnSignalMapping, SLOT(map())); + connect(check, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation())); + + QComboBox* collation = nullptr; + if (!constraint.isNull() && constraint->dialect == Dialect::Sqlite3) + { + collation = new QComboBox(); + collation->setMaximumWidth(ui->colHdrCollation->width()); + collation->setMinimumWidth(ui->colHdrCollation->width() - ui->scrollArea->verticalScrollBar()->width()); + collation->setEditable(true); + collation->lineEdit()->setPlaceholderText(tr("Collate", "table constraints")); + collation->setModel(&collations); + columnsLayout->addWidget(collation, row, col++); + } + + QComboBox* sortOrder = new QComboBox(); + sortOrder->setFixedWidth(ui->colHdrSort->width()); + sortOrder->setToolTip(tr("Sort order", "table constraints")); + columnsLayout->addWidget(sortOrder, row, col++); + + QStringList sortList = {"", sqliteSortOrder(SqliteSortOrder::ASC), sqliteSortOrder(SqliteSortOrder::DESC)}; + sortOrder->addItems(sortList); + + totalColumns++; + + updateColumnState(row); +} + +int TablePrimaryKeyAndUniquePanel::getColumnIndex(const QString& colName) +{ + QWidget* item = nullptr; + QCheckBox* cb = nullptr; + for (int i = 0; i < totalColumns; i++) + { + item = columnsLayout->itemAtPosition(i, 0)->widget(); + cb = qobject_cast<QCheckBox*>(item); + if (cb->text().compare(colName, Qt::CaseInsensitive) == 0) + return i; + } + return -1; +} + +void TablePrimaryKeyAndUniquePanel::updateColumnState(int colIdx) +{ + QWidget* item = columnsLayout->itemAtPosition(colIdx, 0)->widget(); + QCheckBox* cb = qobject_cast<QCheckBox*>(item); + bool enable = cb->isChecked(); + + item = columnsLayout->itemAtPosition(colIdx, 1)->widget(); + qobject_cast<QComboBox*>(item)->setEnabled(enable); + + if (!constraint.isNull() && constraint->dialect == Dialect::Sqlite3) + { + item = columnsLayout->itemAtPosition(colIdx, 2)->widget(); + qobject_cast<QComboBox*>(item)->setEnabled(enable); + } + + updateState(); +} + +void TablePrimaryKeyAndUniquePanel::updateState() +{ + ui->namedLineEdit->setEnabled(ui->namedCheckBox->isChecked()); + ui->conflictComboBox->setEnabled(ui->conflictCheckBox->isChecked()); +} + +void TablePrimaryKeyAndUniquePanel::constraintAvailable() +{ + readCollations(); + buildColumns(); + readConstraint(); +} + +bool TablePrimaryKeyAndUniquePanel::validate() +{ + bool countOk = false; + QWidget* item = nullptr; + QCheckBox* cb = nullptr; + for (int i = 0; i < totalColumns; i++) + { + item = columnsLayout->itemAtPosition(i, 0)->widget(); + cb = qobject_cast<QCheckBox*>(item); + if (cb->isChecked()) + { + countOk = true; + break; + } + } + + bool nameOk = true; + if (ui->namedCheckBox->isChecked() && ui->namedLineEdit->text().isEmpty()) + nameOk = false; + + setValidState(ui->groupBox, countOk, tr("Select at least one column.")); + setValidState(ui->namedLineEdit, nameOk, tr("Enter a name of the constraint.")); + + return countOk && nameOk; +} + + +void TablePrimaryKeyAndUniquePanel::storeConfiguration() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + + // Name + constr->name = QString::null; + if (ui->namedCheckBox->isChecked()) + constr->name = ui->namedLineEdit->text(); + + // On conflict + if (ui->conflictCheckBox->isChecked()) + constr->onConflict = sqliteConflictAlgo(ui->conflictComboBox->currentText()); + + // Columns + foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + delete idxCol; + + constr->indexedColumns.clear(); + + QCheckBox* check = nullptr; + QComboBox* combo = nullptr; + SqliteIndexedColumn* idxCol = nullptr; + QString name; + QString collate; + SqliteSortOrder sortOrder; + for (int i = 0; i < totalColumns; i++) + { + check = dynamic_cast<QCheckBox*>(columnsLayout->itemAtPosition(i, 0)->widget()); + if (!check->isChecked()) + continue; + + name = check->text(); + + if (constr->dialect == Dialect::Sqlite3) + { + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget()); + collate = combo->currentText(); + if (collate.isEmpty()) + collate = QString::null; + + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 2)->widget()); + sortOrder = sqliteSortOrder(combo->currentText()); + } + else + { + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget()); + sortOrder = sqliteSortOrder(combo->currentText()); + } + + idxCol = new SqliteIndexedColumn(name, collate, sortOrder); + idxCol->setParent(constr); + constr->indexedColumns << idxCol; + } +} + +void TablePrimaryKeyAndUniquePanel::readConstraint() +{ + if (constraint.isNull()) + return; + + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + + // Name + if (!constr->name.isNull()) + { + ui->namedCheckBox->setChecked(true); + ui->namedLineEdit->setText(constr->name); + } + + // On conflict + if (constr->onConflict != SqliteConflictAlgo::null) + { + ui->conflictCheckBox->setChecked(true); + ui->conflictComboBox->setCurrentText(sqliteConflictAlgo(constr->onConflict)); + } + + // Columns + int idx; + QCheckBox* check = nullptr; + QComboBox* combo = nullptr; + foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + { + idx = getColumnIndex(idxCol->name); + if (idx < 0) + continue; + + check = dynamic_cast<QCheckBox*>(columnsLayout->itemAtPosition(idx, 0)->widget()); + check->setChecked(true); + + if (constr->dialect == Dialect::Sqlite3) + { + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 1)->widget()); + combo->setCurrentText(idxCol->collate); + + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 2)->widget()); + combo->setCurrentText(sqliteSortOrder(idxCol->sortOrder)); + } + else + { + combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 1)->widget()); + combo->setCurrentText(sqliteSortOrder(idxCol->sortOrder)); + } + } + + if (constr->dialect == Dialect::Sqlite2) + { + ui->colHdrCollation->setVisible(false); + } +} + +void TablePrimaryKeyAndUniquePanel::buildColumns() +{ + totalColumns = 0; + if (constraint.isNull()) + return; + + SqliteCreateTable* createTable = dynamic_cast<SqliteCreateTable*>(constraint->parentStatement()); + int row = 0; + foreach (SqliteCreateTable::Column* column, createTable->columns) + buildColumn(column, row++); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.h new file mode 100644 index 0000000..1092115 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.h @@ -0,0 +1,63 @@ +#ifndef PRIMARYKEYANDUNIQUEPANEL_H +#define PRIMARYKEYANDUNIQUEPANEL_H + +#include "parser/ast/sqlitecreatetable.h" +#include "constraintpanel.h" +#include "guiSQLiteStudio_global.h" +#include <QStringListModel> + +namespace Ui { + class TablePrimaryKeyAndUniquePanel; +} + +class QGridLayout; +class QSignalMapper; + +class GUI_API_EXPORT TablePrimaryKeyAndUniquePanel : public ConstraintPanel +{ + Q_OBJECT + + public: + explicit TablePrimaryKeyAndUniquePanel(QWidget *parent = 0); + ~TablePrimaryKeyAndUniquePanel(); + + bool validate(); + void storeConfiguration(); + + protected: + void changeEvent(QEvent *e); + void constraintAvailable(); + virtual void readConstraint(); + + Ui::TablePrimaryKeyAndUniquePanel *ui = nullptr; + QGridLayout* columnsLayout = nullptr; + + /** + * @brief totalColumns + * Used to count columns created by buildColumns(). + * It's a workaround for QGridLayout::rowCount(), which doesn't return + * number of visible rows, but instead a number of allocated rows, + * which isn't useful in any way. + * This variable lets us to avoid asking for widgets from rows + * that does not exist. + */ + int totalColumns = 0; + + private: + void init(); + void readCollations(); + void buildColumns(); + void buildColumn(SqliteCreateTable::Column* column, int row); + int getColumnIndex(const QString& colName); + + QStringListModel collations; + QSignalMapper* columnSignalMapping = nullptr; + + private slots: + void updateColumnState(int colIdx); + + protected slots: + virtual void updateState(); +}; + +#endif // PRIMARYKEYANDUNIQUEPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.ui new file mode 100644 index 0000000..9453d3c --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.ui @@ -0,0 +1,228 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TablePrimaryKeyAndUniquePanel</class> + <widget class="QWidget" name="TablePrimaryKeyAndUniquePanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>269</height> + </rect> + </property> + <property name="windowTitle"> + <string>PrimaryKeyOrUniquePanel</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Columns</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QWidget" name="columnsHeader" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="colHdrColumn"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Column</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="colHdrCollation"> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Collation</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="colHdrSort"> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Sort</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>364</width> + <height>132</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QCheckBox" name="autoIncrCheckBox"> + <property name="toolTip"> + <string>Valid only for a single column with INTEGER data type</string> + </property> + <property name="text"> + <string>Autoincrement</string> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="namedCheckBox"> + <property name="text"> + <string>Named constraint</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedLineEdit"> + <property name="placeholderText"> + <string>Constraint name</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="conflictWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="conflictCheckBox"> + <property name="text"> + <string>On conflict</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="conflictComboBox"> + <property name="maximumSize"> + <size> + <width>140</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>scrollArea</tabstop> + <tabstop>autoIncrCheckBox</tabstop> + <tabstop>namedCheckBox</tabstop> + <tabstop>namedLineEdit</tabstop> + <tabstop>conflictCheckBox</tabstop> + <tabstop>conflictComboBox</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp new file mode 100644 index 0000000..c538990 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp @@ -0,0 +1,83 @@ +#include "tableprimarykeypanel.h" +#include "ui_tablepkanduniquepanel.h" +#include <QDebug> + +TablePrimaryKeyPanel::TablePrimaryKeyPanel(QWidget *parent) : + TablePrimaryKeyAndUniquePanel(parent) +{ +} + +void TablePrimaryKeyPanel::storeConfiguration() +{ + TablePrimaryKeyAndUniquePanel::storeConfiguration(); + + if (constraint.isNull()) + return; + + // Type + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Constraint::PRIMARY_KEY; + + // Autoincr + constr->autoincrKw = ui->autoIncrCheckBox->isChecked(); +} + + +void TablePrimaryKeyPanel::readConstraint() +{ + TablePrimaryKeyAndUniquePanel::readConstraint(); + + if (constraint.isNull()) + return; + + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + + // Autoincr + if (constr->autoincrKw) + ui->autoIncrCheckBox->setChecked(true); +} + +void TablePrimaryKeyPanel::updateState() +{ + TablePrimaryKeyAndUniquePanel::updateState(); + + // Autoincr + QStringList columns; + QWidget* item = nullptr; + QCheckBox* cb = nullptr; + for (int i = 0; i < totalColumns; i++) + { + item = columnsLayout->itemAtPosition(i, 0)->widget(); + cb = qobject_cast<QCheckBox*>(item); + if (cb->isChecked()) + columns << cb->text(); + } + + if (columns.size() != 1) + { + ui->autoIncrCheckBox->setChecked(false); + ui->autoIncrCheckBox->setEnabled(false); + return; + } + + SqliteCreateTable* createTable = dynamic_cast<SqliteCreateTable*>(constraint->parentStatement()); + QString colName = columns.first(); + SqliteCreateTable::Column* column = createTable->getColumn(colName); + if (!column) + { + qCritical() << "Could not find column when checking for AUTOINCREMENT checkbox state:" << colName + << "\nCreateTable statement:" << createTable->detokenize(); + ui->autoIncrCheckBox->setChecked(false); + ui->autoIncrCheckBox->setEnabled(false); + return; + } + + if (!column->type || column->type->detokenize().trimmed().compare("INTEGER", Qt::CaseInsensitive) != 0) + { + ui->autoIncrCheckBox->setChecked(false); + ui->autoIncrCheckBox->setEnabled(false); + return; + } + + ui->autoIncrCheckBox->setEnabled(true); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.h new file mode 100644 index 0000000..d5e2e59 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.h @@ -0,0 +1,23 @@ +#ifndef PRIMARYKEYPANEL_H +#define PRIMARYKEYPANEL_H + +#include "tablepkanduniquepanel.h" +#include "guiSQLiteStudio_global.h" + +class GUI_API_EXPORT TablePrimaryKeyPanel : public TablePrimaryKeyAndUniquePanel +{ + Q_OBJECT + + public: + explicit TablePrimaryKeyPanel(QWidget *parent = 0); + + void storeConfiguration(); + + private: + void readConstraint(); + + private slots: + void updateState(); +}; + +#endif // PRIMARYKEYPANEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.ui new file mode 100644 index 0000000..76febc9 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.ui @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PrimaryKeyPanel</class> + <widget class="QWidget" name="PrimaryKeyPanel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>269</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Column</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>364</width> + <height>147</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QCheckBox" name="autoIncrCheckBox"> + <property name="text"> + <string>Autoincrement</string> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="namedWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="namedCheckBox"> + <property name="text"> + <string>Named constraint</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="namedLineEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="conflictWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="conflictCheckBox"> + <property name="text"> + <string>On conflict</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox"> + <property name="maximumSize"> + <size> + <width>140</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableuniquepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableuniquepanel.cpp new file mode 100644 index 0000000..14b298e --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableuniquepanel.cpp @@ -0,0 +1,21 @@ +#include "tableuniquepanel.h" +#include "ui_tablepkanduniquepanel.h" + +TableUniquePanel::TableUniquePanel(QWidget *parent) : + TablePrimaryKeyAndUniquePanel(parent) +{ + ui->autoIncrCheckBox->setVisible(false); +} + + +void TableUniquePanel::storeConfiguration() +{ + TablePrimaryKeyAndUniquePanel::storeConfiguration(); + + if (constraint.isNull()) + return; + + // Type + SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data()); + constr->type = SqliteCreateTable::Constraint::UNIQUE; +} diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableuniquepanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/tableuniquepanel.h new file mode 100644 index 0000000..bd77910 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableuniquepanel.h @@ -0,0 +1,16 @@ +#ifndef TABLEUNIQUEPANEL_H +#define TABLEUNIQUEPANEL_H + +#include "tablepkanduniquepanel.h" +#include "guiSQLiteStudio_global.h" + +class GUI_API_EXPORT TableUniquePanel : public TablePrimaryKeyAndUniquePanel +{ + Q_OBJECT + public: + explicit TableUniquePanel(QWidget *parent = 0); + + void storeConfiguration(); +}; + +#endif // TABLEUNIQUEPANEL_H |
