Add column for editing collations to Edit Table dialog

Add a new column to the field table of the Edit Table dialog which
allows you to set, remove, and modify the collation of each field. This
is done by showing a combo box which lists all currently available
collations.

See issue #1973.
This commit is contained in:
Martin Kleusberg
2019-08-21 23:37:16 +02:00
parent 3f0832f449
commit 0768ccd1db
3 changed files with 79 additions and 25 deletions

View File

@@ -48,6 +48,16 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
connect(ui->actionAddCheckConstraint, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::CheckConstraintType); });
ui->buttonAddConstraint->setMenu(constraint_menu);
// Get list of all collations
db.executeSQL("PRAGMA collation_list;", false, true, [this](int column_count, QStringList columns, QStringList) -> bool {
if(column_count >= 2)
m_collationList.push_back(columns.at(1));
return false;
});
if(!m_collationList.contains(""))
m_collationList.push_back("");
m_collationList.sort();
// Editing an existing table?
if(m_bNewTable == false)
{
@@ -194,7 +204,7 @@ void EditTableDialog::populateFields()
}
typeBox->setCurrentIndex(index);
typeBox->installEventFilter(this);
connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypes()));
connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation()));
ui->treeWidget->setItemWidget(tbitem, kType, typeBox);
tbitem->setCheckState(kNotNull, f.notnull() ? Qt::Checked : Qt::Unchecked);
@@ -212,6 +222,21 @@ void EditTableDialog::populateFields()
tbitem->setText(kCheck, QString::fromStdString(f.check()));
QComboBox* collationBox = new QComboBox(ui->treeWidget);
collationBox->setProperty("column", QString::fromStdString(f.name()));
collationBox->addItems(m_collationList);
index = collationBox->findText(QString::fromStdString(f.collation()), Qt::MatchCaseSensitive);
if(index == -1)
{
// some non-existing collation
collationBox->addItem(QString::fromStdString(f.collation()));
index = collationBox->count() - 1;
}
collationBox->setCurrentIndex(index);
collationBox->installEventFilter(this);
connect(collationBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation()));
ui->treeWidget->setItemWidget(tbitem, kCollation, collationBox);
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(m_table.constraint({f.name()}, sqlb::Constraint::ForeignKeyConstraintType));
if(fk)
tbitem->setText(kForeignKey, QString::fromStdString(fk->toString()));
@@ -366,19 +391,33 @@ void EditTableDialog::checkInput()
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
}
void EditTableDialog::updateTypes(QObject *object)
void EditTableDialog::updateTypeAndCollation(QObject* object)
{
QComboBox* typeBox = qobject_cast<QComboBox*>(object);
if(typeBox)
// Get sender combo box and retrieve field name from it
QComboBox* combo = qobject_cast<QComboBox*>(object);
if(!combo)
return;
QString column = combo->property("column").toString();
// Get type *and* collation combo box for this field
auto item = ui->treeWidget->findItems(column, Qt::MatchExactly, kName);
if(item.size() != 1)
return;
QComboBox* typeBox = qobject_cast<QComboBox*>(ui->treeWidget->itemWidget(item.front(), kType));
QComboBox* collationBox = qobject_cast<QComboBox*>(ui->treeWidget->itemWidget(item.front(), kCollation));
// Update table
if(typeBox && collationBox)
{
QString type = typeBox->currentText();
std::string column = typeBox->property("column").toString().toStdString();
QString collation = collationBox->currentText();
for(size_t index=0; index < m_table.fields.size(); ++index)
{
if(m_table.fields.at(index).name() == column)
if(m_table.fields.at(index).name() == column.toStdString())
{
m_table.fields.at(index).setType(type.toStdString());
m_table.fields.at(index).setCollation(collation.toStdString());
break;
}
}
@@ -387,16 +426,16 @@ void EditTableDialog::updateTypes(QObject *object)
}
}
void EditTableDialog::updateTypes()
void EditTableDialog::updateTypeAndCollation()
{
updateTypes(sender());
updateTypeAndCollation(sender());
}
bool EditTableDialog::eventFilter(QObject *object, QEvent *event)
{
if(event->type() == QEvent::FocusOut)
{
updateTypes(object);
updateTypeAndCollation(object);
}
return false;
}
@@ -481,7 +520,8 @@ void EditTableDialog::fieldItemChanged(QTreeWidgetItem *item, int column)
populateConstraints();
} break;
case kType:
// see updateTypes() SLOT
case kCollation:
// see updateTypeAndCollation() SLOT
break;
case kPrimaryKey:
{
@@ -729,7 +769,7 @@ void EditTableDialog::addField()
ui->treeWidget->setItemWidget(tbitem, kType, typeBox);
typeBox->installEventFilter(this);
connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypes()));
connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation()));
tbitem->setCheckState(kNotNull, Qt::Unchecked);
tbitem->setCheckState(kPrimaryKey, Qt::Unchecked);
@@ -815,21 +855,28 @@ void EditTableDialog::moveCurrentField(bool down)
int currentRow = ui->treeWidget->currentIndex().row();
int newRow = currentRow + (down ? 1 : -1);
// Save the combobox first by making a copy
QComboBox* oldCombo = qobject_cast<QComboBox*>(ui->treeWidget->itemWidget(ui->treeWidget->topLevelItem(currentRow), kType));
QComboBox* newCombo = new QComboBox(ui->treeWidget);
newCombo->setProperty("column", oldCombo->property("column"));
newCombo->installEventFilter(this);
connect(newCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypes()));
newCombo->setEditable(true);
for(int i=0; i < oldCombo->count(); ++i)
newCombo->addItem(oldCombo->itemText(i));
newCombo->setCurrentIndex(oldCombo->currentIndex());
// Save the comboboxes first by making copies
QComboBox* newCombo[2];
for(int c=0;c<2;c++)
{
int column = (c == 0 ? kType : kCollation);
QComboBox* oldCombo = qobject_cast<QComboBox*>(ui->treeWidget->itemWidget(ui->treeWidget->topLevelItem(currentRow), column));
newCombo[c] = new QComboBox(ui->treeWidget);
newCombo[c]->setProperty("column", oldCombo->property("column"));
newCombo[c]->installEventFilter(this);
connect(newCombo[c], SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation()));
newCombo[c]->setEditable(oldCombo->isEditable());
for(int i=0; i < oldCombo->count(); ++i)
newCombo[c]->addItem(oldCombo->itemText(i));
newCombo[c]->setCurrentIndex(oldCombo->currentIndex());
}
// Now, just remove the item and insert it at it's new position, then restore the combobox
QTreeWidgetItem* item = ui->treeWidget->takeTopLevelItem(currentRow);
ui->treeWidget->insertTopLevelItem(newRow, item);
ui->treeWidget->setItemWidget(item, kType, newCombo);
ui->treeWidget->setItemWidget(item, kType, newCombo[0]);
ui->treeWidget->setItemWidget(item, kCollation, newCombo[1]);
// Select the old item at its new position
ui->treeWidget->setCurrentIndex(ui->treeWidget->currentIndex().sibling(newRow, 0));

View File

@@ -39,7 +39,8 @@ private:
kUnique = 5,
kDefault = 6,
kCheck = 7,
kForeignKey = 8
kCollation = 8,
kForeignKey = 9
};
enum ConstraintColumns {
@@ -65,9 +66,9 @@ private slots:
void checkInput();
void fieldItemChanged(QTreeWidgetItem* item, int column);
void constraintItemChanged(QTableWidgetItem* item);
void updateTypes(QObject *object);
void updateTypeAndCollation(QObject *object);
bool eventFilter(QObject *object, QEvent *event) override;
void updateTypes();
void updateTypeAndCollation();
void moveUp();
void moveDown();
void setWithoutRowid(bool without_rowid);
@@ -84,6 +85,7 @@ private:
sqlb::Table m_table;
bool m_bNewTable;
QString m_sRestorePointName;
QStringList m_collationList;
};
#endif

View File

@@ -275,6 +275,11 @@
<string>Check constraint</string>
</property>
</column>
<column>
<property name="text">
<string>Collation</string>
</property>
</column>
<column>
<property name="text">
<string>Foreign Key</string>