Skip to content

Commit

Permalink
Merge pull request #5039 from tuffnatty/feature/icu_collations
Browse files Browse the repository at this point in the history
Extension-based collations in the Collations editor
  • Loading branch information
pawelsalawa authored Aug 12, 2024
2 parents 742302a + bd3bfa3 commit 1edfa33
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 13 deletions.
6 changes: 6 additions & 0 deletions SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,12 @@ bool AbstractDb3<T>::registerCollationInternal(const QString& name)
if (!dbHandle)
return false;

CollationManager::CollationPtr collation = COLLATIONS->getCollation(name);
if (collation == nullptr)
return false;
if (collation->type == CollationManager::CollationType::EXTENSION_BASED)
return !(exec(collation->code, Flag::NO_LOCK)->isError());

CollationUserData* userData = new CollationUserData;
userData->name = name;

Expand Down
7 changes: 7 additions & 0 deletions SQLiteStudio3/coreSQLiteStudio/services/collationmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ class API_EXPORT CollationManager : public QObject
Q_OBJECT

public:
enum CollationType
{
FUNCTION_BASED = 0,
EXTENSION_BASED = 1
};
struct API_EXPORT Collation
{
QString name;
CollationType type;
QString lang;
QString code;
QStringList databases;
Expand All @@ -30,6 +36,7 @@ class API_EXPORT CollationManager : public QObject
virtual QList<CollationPtr> getCollationsForDatabase(const QString& dbName) const = 0;
virtual int evaluate(const QString& name, const QString& value1, const QString& value2) = 0;
virtual int evaluateDefault(const QString& value1, const QString& value2) = 0;
virtual CollationPtr getCollation(const QString &name) const = 0;

signals:
void collationListChanged();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ QList<CollationManager::CollationPtr> CollationManagerImpl::getAllCollations() c
return collations;
}

CollationManager::CollationPtr CollationManagerImpl::getCollation(const QString &name) const
{
if (!collationsByKey.contains(name))
{
qCritical() << "Could not find requested collation" << name << ".";
return nullptr;
}
return collationsByKey[name];
}

QList<CollationManager::CollationPtr> CollationManagerImpl::getCollationsForDatabase(const QString& dbName) const
{
QList<CollationPtr> results;
Expand Down Expand Up @@ -98,6 +108,7 @@ void CollationManagerImpl::storeInConfig()
for (CollationPtr coll : collations)
{
collHash["name"] = coll->name;
collHash["type"] = coll->type;
collHash["lang"] = coll->lang;
collHash["code"] = coll->code;
collHash["allDatabases"] = coll->allDatabases;
Expand All @@ -119,6 +130,10 @@ void CollationManagerImpl::loadFromConfig()
collHash = var.toHash();
coll = CollationPtr::create();
coll->name = collHash["name"].toString();
if (collHash.contains("type") && collHash["type"].toInt() == CollationType::EXTENSION_BASED)
coll->type = CollationType::EXTENSION_BASED;
else
coll->type = CollationType::FUNCTION_BASED;
coll->lang = updateScriptingQtLang(collHash["lang"].toString());
coll->code = collHash["code"].toString();
coll->databases = collHash["databases"].toStringList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class API_EXPORT CollationManagerImpl : public CollationManager
QList<CollationPtr> getCollationsForDatabase(const QString& dbName) const;
int evaluate(const QString& name, const QString& value1, const QString& value2);
int evaluateDefault(const QString& value1, const QString& value2);
CollationPtr getCollation(const QString &name) const;

private:
void init();
Expand Down
62 changes: 56 additions & 6 deletions SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ void CollationsEditor::init()
connect(ui->nameEdit, SIGNAL(textChanged(QString)), this, SLOT(updateModified()));
connect(ui->allDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
connect(ui->selectedDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
connect(ui->functionBasedRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
connect(ui->extensionBasedRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
connect(ui->langCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(updateModified()));

connect(dbListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateModified()));
connect(CFG_UI.Fonts.SqlEditor, SIGNAL(changed(QVariant)), this, SLOT(changeFont(QVariant)));

// Language plugins
for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>())
ui->langCombo->addItem(plugin->getLanguage());
updateLangCombo();

// Syntax highlighting plugins
for (SyntaxHighlighterPlugin* plugin : PLUGINS->getLoadedPlugins<SyntaxHighlighterPlugin>())
Expand All @@ -130,9 +130,16 @@ int CollationsEditor::getCurrentCollationRow() const
return idxList.first().row();
}

CollationManager::CollationType CollationsEditor::getCurrentType() const
{
return ui->extensionBasedRadio->isChecked() ? CollationManager::CollationType::EXTENSION_BASED
: CollationManager::CollationType::FUNCTION_BASED;
}

void CollationsEditor::collationDeselected(int row)
{
model->setName(row, ui->nameEdit->text());
model->setType(row, getCurrentType());
model->setLang(row, ui->langCombo->currentText());
model->setAllDatabases(row, ui->allDatabasesRadio->isChecked());
model->setCode(row, ui->codeEdit->toPlainText());
Expand All @@ -149,6 +156,9 @@ void CollationsEditor::collationSelected(int row)
updatesForSelection = true;
ui->nameEdit->setText(model->getName(row));
ui->codeEdit->setPlainText(model->getCode(row));
ui->functionBasedRadio->setChecked(model->getType(row) == CollationManager::CollationType::FUNCTION_BASED);
ui->extensionBasedRadio->setChecked(model->getType(row) == CollationManager::CollationType::EXTENSION_BASED);
updateLangCombo();
ui->langCombo->setCurrentText(model->getLang(row));

// Databases
Expand Down Expand Up @@ -238,7 +248,7 @@ void CollationsEditor::newCollation()

CollationManager::CollationPtr coll = CollationManager::CollationPtr::create();
coll->name = generateUniqueName("collation", model->getCollationNames());

coll->type = getCurrentType();
if (ui->langCombo->currentIndex() > -1)
coll->lang = ui->langCombo->currentText();

Expand Down Expand Up @@ -287,6 +297,8 @@ void CollationsEditor::updateCurrentCollationState()
bool nameOk = model->isAllowedName(row, name) && !name.trimmed().isEmpty();
setValidState(ui->nameEdit, nameOk, tr("Enter a non-empty, unique name of the collation."));

updateLangCombo();

bool langOk = ui->langCombo->currentIndex() >= 0;
ui->codeGroup->setEnabled(langOk);
ui->databasesGroup->setEnabled(langOk);
Expand All @@ -296,7 +308,16 @@ void CollationsEditor::updateCurrentCollationState()
setValidState(ui->langCombo, langOk, tr("Pick the implementation language."));

bool codeOk = !ui->codeEdit->toPlainText().trimmed().isEmpty();
setValidState(ui->codeEdit, codeOk, tr("Enter a non-empty implementation code."));
if (ui->extensionBasedRadio->isChecked())
{
ui->codeGroup->setTitle(tr("Registration code"));
setValidState(ui->codeEdit, codeOk, tr("Enter a non-empty registration code."));
}
else
{
ui->codeGroup->setTitle(tr("Implementation code"));
setValidState(ui->codeEdit, codeOk, tr("Enter a non-empty implementation code."));
}

// Syntax highlighter
QString lang = ui->langCombo->currentText();
Expand Down Expand Up @@ -343,6 +364,34 @@ void CollationsEditor::collationSelected(const QItemSelection& selected, const Q
}
}

void CollationsEditor::updateLangCombo()
{
QComboBox *combo = ui->langCombo;
bool alreadyInternalUpdate = updatesForSelection;
updatesForSelection = true;
if (ui->extensionBasedRadio->isChecked())
{
if (combo->isEnabled())
{
combo->setEnabled(false);
combo->clear();
combo->addItem("SQL");
combo->setCurrentIndex(0);
}
}
else
{
if (!combo->isEnabled())
{
combo->clear();
for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>())
combo->addItem(plugin->getLanguage());
combo->setEnabled(true);
}
}
updatesForSelection = alreadyInternalUpdate;
}

void CollationsEditor::updateModified()
{
if (updatesForSelection)
Expand All @@ -353,11 +402,12 @@ void CollationsEditor::updateModified()
{
bool nameDiff = model->getName(row) != ui->nameEdit->text();
bool codeDiff = model->getCode(row) != ui->codeEdit->toPlainText();
bool typeDiff = model->getType(row) != getCurrentType();
bool langDiff = model->getLang(row) != ui->langCombo->currentText();
bool allDatabasesDiff = model->getAllDatabases(row) != ui->allDatabasesRadio->isChecked();
bool dbDiff = toSet(getCurrentDatabases()) != toSet(model->getDatabases(row)); // QSet to ignore order

currentModified = (nameDiff || codeDiff || langDiff || allDatabasesDiff || dbDiff);
currentModified = (nameDiff || codeDiff || typeDiff || langDiff || allDatabasesDiff || dbDiff);
}

updateCurrentCollationState();
Expand Down
3 changes: 3 additions & 0 deletions SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "mdichild.h"
#include "common/extactioncontainer.h"
#include "services/collationmanager.h"
#include <QItemSelection>
#include <QModelIndex>
#include <QWidget>
Expand Down Expand Up @@ -61,12 +62,14 @@ class GUI_API_EXPORT CollationsEditor : public MdiChild
private:
void init();
int getCurrentCollationRow() const;
CollationManager::CollationType getCurrentType() const;
void collationDeselected(int row);
void collationSelected(int row);
void clearEdits();
void selectCollation(int row);
QStringList getCurrentDatabases() const;
void setFont(const QFont& font);
void updateLangCombo();

Ui::CollationsEditor *ui = nullptr;
CollationsEditorModel* model = nullptr;
Expand Down
27 changes: 26 additions & 1 deletion SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,38 @@
<widget class="QLineEdit" name="nameEdit"/>
</item>
<item row="0" column="1">
<widget class="QLabel" name="typeLabel">
<property name="text">
<string>Collation type:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QRadioButton" name="functionBasedRadio">
<property name="text">
<string>Function-based</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="extensionBasedRadio">
<property name="text">
<string>Extension-based</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<widget class="QLabel" name="langLabel">
<property name="text">
<string>Implementation language:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="1" column="2">
<widget class="QComboBox" name="langCombo"/>
</item>
</layout>
Expand Down
27 changes: 21 additions & 6 deletions SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "collationseditormodel.h"
#include "common/unused.h"
#include "common/strhash.h"
#include "iconmanager.h"
#include "services/pluginmanager.h"
#include "plugins/scriptingplugin.h"
#include "icon.h"
Expand Down Expand Up @@ -69,6 +70,16 @@ QString CollationsEditorModel::getName(int row) const
GETTER(collationList[row]->data->name, QString());
}

void CollationsEditorModel::setType(int row, CollationManager::CollationType type)
{
SETTER(collationList[row]->data->type, type);
}

CollationManager::CollationType CollationsEditorModel::getType(int row) const
{
GETTER(collationList[row]->data->type, CollationManager::CollationType::FUNCTION_BASED);
}

void CollationsEditorModel::setLang(int row, const QString& lang)
{
SETTER(collationList[row]->data->lang, lang);
Expand Down Expand Up @@ -248,13 +259,17 @@ QVariant CollationsEditorModel::data(const QModelIndex& index, int role) const
if (role == Qt::DisplayRole)
return collationList[index.row()]->data->name;

if (role == Qt::DecorationRole && langToIcon.contains(collationList[index.row()]->data->lang))
if (role == Qt::DecorationRole)
{
QIcon icon = langToIcon[collationList[index.row()]->data->lang];
if (!collationList[index.row()]->valid)
icon = Icon::merge(icon, Icon::ERROR);

return icon;
auto coll = collationList[index.row()]->data;
bool isExtension = coll->type == CollationManager::CollationType::EXTENSION_BASED;
if (isExtension || langToIcon.contains(coll->lang))
{
QIcon icon = isExtension ? ICONS.EXTENSION : langToIcon[coll->lang];
if (!collationList[index.row()]->valid)
icon = Icon::merge(icon, Icon::ERROR);
return icon;
}
}

return QVariant();
Expand Down
2 changes: 2 additions & 0 deletions SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class GUI_API_EXPORT CollationsEditorModel : public QAbstractListModel
void setModified(int row, bool modified);
void setName(int row, const QString& name);
QString getName(int row) const;
void setType(int row, CollationManager::CollationType type);
CollationManager::CollationType getType(int row) const;
void setLang(int row, const QString& lang);
QString getLang(int row) const;
void setAllDatabases(int row, bool allDatabases);
Expand Down

0 comments on commit 1edfa33

Please sign in to comment.