Verified Commit 988bcc37 authored by Fushan Wen's avatar Fushan Wen 💬
Browse files

applets/dict: add EnabledDictModel to show enabled dictionaries

The model will be initialized after the dict list is fetched.

CCBUG: 453878
parent bc8d35ba
......@@ -18,6 +18,8 @@ void DictPlugin::registerTypes(const char *uri)
qRegisterMetaType<QAbstractSocket::SocketError>();
qmlRegisterAnonymousType<QAbstractListModel>("", 1);
qmlRegisterType<DictObject>(uri, 1, 0, "DictObject");
qmlRegisterType<DictionariesModel>(uri, 1, 0, "DictionariesModel");
......
......@@ -7,19 +7,105 @@
#include "dictionariesmodel.h"
#include <QDebug>
EnabledDictModel::EnabledDictModel(QObject *parent)
: QAbstractListModel(parent)
{
}
QVariant EnabledDictModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index)) {
return {};
}
const int row = index.row();
switch (role) {
case Qt::DisplayRole:
return m_enabledDicts[row].description;
case Qt::EditRole:
return m_enabledDicts[row].id;
default:
return {};
}
}
int EnabledDictModel::rowCount(const QModelIndex &index) const
{
return index.isValid() ? 0 : m_enabledDicts.size();
}
QHash<int, QByteArray> EnabledDictModel::roleNames() const
{
return {
{Qt::DisplayRole, "description"},
{Qt::EditRole, "id"},
};
}
bool EnabledDictModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
{
if (sourceParent != destinationParent || sourceParent.isValid()) {
return false;
}
const bool isMoveDown = destinationChild > sourceRow;
// QAbstractItemModel::beginMoveRows(): when moving rows down in the same parent,
// the rows will be placed before the destinationChild index.
if (!beginMoveRows(sourceParent, sourceRow + count - 1, sourceRow, destinationParent, isMoveDown ? destinationChild + 1 : destinationChild)) {
return false;
}
for (int i = 0; i < count; i++) {
m_enabledDicts.move(isMoveDown ? sourceRow : sourceRow + i, destinationChild);
}
endMoveRows();
return true;
}
void EnabledDictModel::appendDict(const AvailableDict &dict)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_enabledDicts.append(dict);
endInsertRows();
}
void EnabledDictModel::removeDict(int _index)
{
if (_index < 0 || _index >= rowCount()) {
return;
}
beginRemoveRows(QModelIndex(), _index, _index);
m_enabledDicts.removeAt(_index);
endRemoveRows();
}
DictionariesModel::DictionariesModel(QObject *parent)
: QAbstractListModel(parent)
, m_enabledDictModel(new EnabledDictModel(this))
{
connect(&m_engine, &DictEngine::dictErrorOccurred, this, &DictionariesModel::slotDictErrorOccurred);
connect(&m_engine, &DictEngine::dictsRecieved, this, [this](const QMap<QString, QString> &dicts) {
beginResetModel();
m_availableDicts = {};
m_idIndexProxyMap.clear();
m_availableDicts.resize(dicts.count());
m_idIndexProxyMap.reserve(dicts.size());
int i = 0;
for (auto it = dicts.begin(), end = dicts.end(); it != end; ++it, ++i) {
m_availableDicts[i] = AvailableDict{it.key(), it.value()};
m_idIndexProxyMap.emplace(it.key(), i);
}
endResetModel();
setEnabledDicts(m_enabledDicts);
});
connect(&m_engine, &DictEngine::dictLoadingChanged, this, &DictionariesModel::slotDictLoadingChanged);
......@@ -34,12 +120,38 @@ QVariant DictionariesModel::data(const QModelIndex &index, int role) const
return m_availableDicts[row].description;
case Qt::EditRole:
return m_availableDicts[row].id;
case Qt::CheckStateRole:
return m_availableDicts[row].enabled;
default:
break;
}
return QVariant();
}
bool DictionariesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!checkIndex(index)) {
return false;
}
const int row = index.row();
switch (role) {
case Qt::CheckStateRole: {
if (value.toBool()) {
setEnabled(m_availableDicts[row].id);
} else {
setDisabled(m_enabledDictIdList.indexOf(m_availableDicts[row].id));
}
return true;
}
default:
return false;
}
}
int DictionariesModel::rowCount(const QModelIndex &index) const
{
if (index.isValid()) {
......@@ -50,7 +162,124 @@ int DictionariesModel::rowCount(const QModelIndex &index) const
QHash<int, QByteArray> DictionariesModel::roleNames() const
{
return {{Qt::DisplayRole, "description"}, {Qt::EditRole, "id"}};
return {
{Qt::DisplayRole, "description"},
{Qt::EditRole, "id"},
{Qt::CheckStateRole, "checked"},
};
}
QString DictionariesModel::enabledDicts() const
{
return m_enabledDictIdList.join(QLatin1Char(','));
}
void DictionariesModel::setEnabledDicts(const QString &dicts)
{
m_enabledDicts = dicts;
if (!dicts.isEmpty()) {
m_enabledDictIdList = dicts.split(QLatin1Char(','), Qt::SkipEmptyParts);
} else {
m_enabledDictIdList.clear();
}
Q_EMIT enabledDictsChanged();
if (m_availableDicts.empty()) {
// Loading
return;
}
std::vector<AvailableDict> enabledDictList;
enabledDictList.resize(m_enabledDictIdList.size());
for (std::size_t i = 0; i < m_availableDicts.size(); i++) {
auto &dict = m_availableDicts.at(i);
auto it = std::find_if(m_enabledDictIdList.cbegin(), m_enabledDictIdList.cend(), [&dict](const QString &id) {
return id == dict.id;
});
const bool enabled = it != m_enabledDictIdList.cend();
if (dict.enabled != enabled) {
dict.enabled = enabled;
Q_EMIT dataChanged(index(i, 0), index(i, 0), {Qt::CheckStateRole});
}
if (enabled) {
enabledDictList[std::distance(m_enabledDictIdList.cbegin(), it)] = dict;
}
}
for (const auto &dict : std::as_const(enabledDictList)) {
if (!dict.enabled) {
continue;
}
m_enabledDictModel->appendDict(dict);
}
}
QAbstractListModel *DictionariesModel::enabledDictModel() const
{
return m_enabledDictModel;
}
void DictionariesModel::setEnabled(const QString &dict)
{
const auto it = m_idIndexProxyMap.find(dict);
if (it == m_idIndexProxyMap.end()) {
return;
}
auto &d = m_availableDicts.at(it->second);
if (d.enabled) {
return;
}
d.enabled = true;
Q_EMIT dataChanged(index(it->second, 0), index(it->second, 0), {Qt::CheckStateRole});
if (!m_enabledDictIdList.contains(d.id)) {
m_enabledDictIdList.append(d.id);
m_enabledDictModel->appendDict(d);
Q_EMIT enabledDictsChanged();
}
}
void DictionariesModel::setDisabled(int _index)
{
if (_index < 0 || _index >= m_enabledDictIdList.size()) {
return;
}
m_enabledDictModel->removeDict(_index);
const QString id = m_enabledDictIdList.takeAt(_index);
Q_EMIT enabledDictsChanged();
const auto it = m_idIndexProxyMap.find(id);
if (it == m_idIndexProxyMap.end()) {
return;
}
auto &d = m_availableDicts.at(it->second);
d.enabled = false;
Q_EMIT dataChanged(index(it->second, 0), index(it->second, 0), {Qt::CheckStateRole});
}
void DictionariesModel::move(int oldIndex, int newIndex)
{
if (oldIndex < 0 || oldIndex >= m_enabledDictIdList.size()) {
return;
}
if (newIndex < 0 || newIndex >= m_enabledDictIdList.size()) {
return;
}
m_enabledDictModel->moveRows(QModelIndex(), oldIndex, 1, QModelIndex(), newIndex);
m_enabledDictIdList.move(oldIndex, newIndex);
Q_EMIT enabledDictsChanged();
}
bool DictionariesModel::loading() const
......
......@@ -7,14 +7,50 @@
#define DICTIONARIES_MODEL_H
#include "../../dict/dictengine.h"
#include <unordered_map>
#include <QAbstractListModel>
#include <QAbstractSocket>
#include <vector>
struct AvailableDict {
QString id;
QString description;
bool enabled = false;
};
class EnabledDictModel : public QAbstractListModel
{
public:
explicit EnabledDictModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
void appendDict(const AvailableDict &dict);
void removeDict(int _index);
private:
QList<AvailableDict> m_enabledDicts;
};
class DictionariesModel : public QAbstractListModel
{
Q_OBJECT
/**
* @return the list of enabled dictionaries
*/
Q_PROPERTY(QString enabledDicts READ enabledDicts WRITE setEnabledDicts NOTIFY enabledDictsChanged)
/**
* @return the model that contains all enabled dictionaries
*/
Q_PROPERTY(QAbstractListModel *enabledDictModel READ enabledDictModel CONSTANT)
/**
* @return @c true if the engine is downloading dict list from
* the Internet, @c false otherwise.
......@@ -35,15 +71,26 @@ public:
explicit DictionariesModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
int rowCount(const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
QString enabledDicts() const;
void setEnabledDicts(const QString &dicts);
QAbstractListModel *enabledDictModel() const;
Q_INVOKABLE void setEnabled(const QString &dict);
Q_INVOKABLE void setDisabled(int _index);
Q_INVOKABLE void move(int oldIndex, int newIndex);
bool loading() const;
QAbstractSocket::SocketError errorCode() const;
QString errorString() const;
Q_SIGNALS:
void enabledDictsChanged();
void loadingChanged();
void errorCodeChanged();
void errorStringChanged();
......@@ -56,12 +103,12 @@ private:
void setAvailableDicts(const QVariantMap &data);
DictEngine m_engine;
EnabledDictModel *m_enabledDictModel;
struct AvailableDict {
QString id;
QString description;
};
std::vector<AvailableDict> m_availableDicts;
std::unordered_map<QString /*id*/, int /*index*/> m_idIndexProxyMap;
QString m_enabledDicts;
QStringList m_enabledDictIdList;
bool m_loading = false;
QAbstractSocket::SocketError m_errorCode = QAbstractSocket::UnknownSocketError;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment