File indexing completed on 2024-05-19 16:31:38

0001 /*
0002  * SPDX-FileCopyrightText: 2017 David Faure <faure@kde.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 
0007 #include "dictionariesmodel.h"
0008 #include <QDebug>
0009 
0010 EnabledDictModel::EnabledDictModel(QObject *parent)
0011     : QAbstractListModel(parent)
0012 {
0013 }
0014 
0015 QVariant EnabledDictModel::data(const QModelIndex &index, int role) const
0016 {
0017     if (!checkIndex(index)) {
0018         return {};
0019     }
0020 
0021     const int row = index.row();
0022 
0023     switch (role) {
0024     case Qt::DisplayRole:
0025         return m_enabledDicts[row].description;
0026     case Qt::EditRole:
0027         return m_enabledDicts[row].id;
0028     default:
0029         return {};
0030     }
0031 }
0032 
0033 int EnabledDictModel::rowCount(const QModelIndex &index) const
0034 {
0035     return index.isValid() ? 0 : m_enabledDicts.size();
0036 }
0037 
0038 QHash<int, QByteArray> EnabledDictModel::roleNames() const
0039 {
0040     return {
0041         {Qt::DisplayRole, "description"},
0042         {Qt::EditRole, "id"},
0043     };
0044 }
0045 
0046 bool EnabledDictModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
0047 {
0048     if (sourceParent != destinationParent || sourceParent.isValid()) {
0049         return false;
0050     }
0051 
0052     const bool isMoveDown = destinationChild > sourceRow;
0053     // QAbstractItemModel::beginMoveRows(): when moving rows down in the same parent,
0054     // the rows will be placed before the destinationChild index.
0055     if (!beginMoveRows(sourceParent, sourceRow + count - 1, sourceRow, destinationParent, isMoveDown ? destinationChild + 1 : destinationChild)) {
0056         return false;
0057     }
0058 
0059     for (int i = 0; i < count; i++) {
0060         m_enabledDicts.move(isMoveDown ? sourceRow : sourceRow + i, destinationChild);
0061     }
0062 
0063     endMoveRows();
0064     return true;
0065 }
0066 
0067 void EnabledDictModel::appendDict(const AvailableDict &dict)
0068 {
0069     beginInsertRows(QModelIndex(), rowCount(), rowCount());
0070 
0071     m_enabledDicts.append(dict);
0072 
0073     endInsertRows();
0074 }
0075 
0076 void EnabledDictModel::removeDict(int _index)
0077 {
0078     if (_index < 0 || _index >= rowCount()) {
0079         return;
0080     }
0081 
0082     beginRemoveRows(QModelIndex(), _index, _index);
0083 
0084     m_enabledDicts.removeAt(_index);
0085 
0086     endRemoveRows();
0087 }
0088 
0089 DictionariesModel::DictionariesModel(QObject *parent)
0090     : QAbstractListModel(parent)
0091     , m_enabledDictModel(new EnabledDictModel(this))
0092 {
0093     connect(&m_engine, &DictEngine::dictErrorOccurred, this, &DictionariesModel::slotDictErrorOccurred);
0094     connect(&m_engine, &DictEngine::dictsRecieved, this, [this](const QMap<QString, QString> &dicts) {
0095         beginResetModel();
0096         m_availableDicts = {};
0097         m_idIndexProxyMap.clear();
0098         m_availableDicts.resize(dicts.count());
0099         m_idIndexProxyMap.reserve(dicts.size());
0100 
0101         int i = 0;
0102         for (auto it = dicts.begin(), end = dicts.end(); it != end; ++it, ++i) {
0103             m_availableDicts[i] = AvailableDict{it.key(), it.value()};
0104             m_idIndexProxyMap.emplace(it.key(), i);
0105         }
0106         endResetModel();
0107 
0108         setEnabledDicts(m_enabledDicts);
0109     });
0110     connect(&m_engine, &DictEngine::dictLoadingChanged, this, &DictionariesModel::slotDictLoadingChanged);
0111 
0112     m_engine.requestDicts();
0113 }
0114 
0115 QVariant DictionariesModel::data(const QModelIndex &index, int role) const
0116 {
0117     const int row = index.row();
0118     switch (role) {
0119     case Qt::DisplayRole:
0120         return m_availableDicts[row].description;
0121     case Qt::EditRole:
0122         return m_availableDicts[row].id;
0123     case Qt::CheckStateRole:
0124         return m_availableDicts[row].enabled;
0125     default:
0126         break;
0127     }
0128     return QVariant();
0129 }
0130 
0131 bool DictionariesModel::setData(const QModelIndex &index, const QVariant &value, int role)
0132 {
0133     if (!checkIndex(index)) {
0134         return false;
0135     }
0136 
0137     const int row = index.row();
0138 
0139     switch (role) {
0140     case Qt::CheckStateRole: {
0141         if (value.toBool()) {
0142             setEnabled(m_availableDicts[row].id);
0143         } else {
0144             setDisabled(m_enabledDictIdList.indexOf(m_availableDicts[row].id));
0145         }
0146 
0147         return true;
0148     }
0149 
0150     default:
0151         return false;
0152     }
0153 }
0154 
0155 int DictionariesModel::rowCount(const QModelIndex &index) const
0156 {
0157     if (index.isValid()) {
0158         return 0; // flat model
0159     }
0160     return m_availableDicts.size();
0161 }
0162 
0163 QHash<int, QByteArray> DictionariesModel::roleNames() const
0164 {
0165     return {
0166         {Qt::DisplayRole, "description"},
0167         {Qt::EditRole, "id"},
0168         {Qt::CheckStateRole, "checked"},
0169     };
0170 }
0171 
0172 QString DictionariesModel::enabledDicts() const
0173 {
0174     return m_enabledDictIdList.join(QLatin1Char(','));
0175 }
0176 
0177 void DictionariesModel::setEnabledDicts(const QString &dicts)
0178 {
0179     m_enabledDicts = dicts;
0180     if (!dicts.isEmpty()) {
0181         m_enabledDictIdList = dicts.split(QLatin1Char(','), Qt::SkipEmptyParts);
0182     } else {
0183         m_enabledDictIdList.clear();
0184     }
0185     Q_EMIT enabledDictsChanged();
0186 
0187     if (m_availableDicts.empty()) {
0188         // Loading
0189         return;
0190     }
0191 
0192     std::vector<AvailableDict> enabledDictList;
0193     enabledDictList.resize(m_enabledDictIdList.size());
0194 
0195     for (std::size_t i = 0; i < m_availableDicts.size(); i++) {
0196         auto &dict = m_availableDicts.at(i);
0197         auto it = std::find_if(m_enabledDictIdList.cbegin(), m_enabledDictIdList.cend(), [&dict](const QString &id) {
0198             return id == dict.id;
0199         });
0200         const bool enabled = it != m_enabledDictIdList.cend();
0201 
0202         if (dict.enabled != enabled) {
0203             dict.enabled = enabled;
0204             Q_EMIT dataChanged(index(i, 0), index(i, 0), {Qt::CheckStateRole});
0205         }
0206 
0207         if (enabled) {
0208             enabledDictList[std::distance(m_enabledDictIdList.cbegin(), it)] = dict;
0209         }
0210     }
0211 
0212     for (const auto &dict : std::as_const(enabledDictList)) {
0213         if (!dict.enabled) {
0214             continue;
0215         }
0216 
0217         m_enabledDictModel->appendDict(dict);
0218     }
0219 }
0220 
0221 QAbstractListModel *DictionariesModel::enabledDictModel() const
0222 {
0223     return m_enabledDictModel;
0224 }
0225 
0226 void DictionariesModel::setEnabled(const QString &dict)
0227 {
0228     const auto it = m_idIndexProxyMap.find(dict);
0229     if (it == m_idIndexProxyMap.end()) {
0230         return;
0231     }
0232 
0233     auto &d = m_availableDicts.at(it->second);
0234     if (d.enabled) {
0235         return;
0236     }
0237 
0238     d.enabled = true;
0239     Q_EMIT dataChanged(index(it->second, 0), index(it->second, 0), {Qt::CheckStateRole});
0240 
0241     if (!m_enabledDictIdList.contains(d.id)) {
0242         m_enabledDictIdList.append(d.id);
0243         m_enabledDictModel->appendDict(d);
0244 
0245         Q_EMIT enabledDictsChanged();
0246     }
0247 }
0248 
0249 void DictionariesModel::setDisabled(int _index)
0250 {
0251     if (_index < 0 || _index >= m_enabledDictIdList.size()) {
0252         return;
0253     }
0254 
0255     m_enabledDictModel->removeDict(_index);
0256 
0257     const QString id = m_enabledDictIdList.takeAt(_index);
0258     Q_EMIT enabledDictsChanged();
0259 
0260     const auto it = m_idIndexProxyMap.find(id);
0261     if (it == m_idIndexProxyMap.end()) {
0262         return;
0263     }
0264 
0265     auto &d = m_availableDicts.at(it->second);
0266     d.enabled = false;
0267     Q_EMIT dataChanged(index(it->second, 0), index(it->second, 0), {Qt::CheckStateRole});
0268 }
0269 
0270 void DictionariesModel::move(int oldIndex, int newIndex)
0271 {
0272     if (oldIndex < 0 || oldIndex >= m_enabledDictIdList.size()) {
0273         return;
0274     }
0275     if (newIndex < 0 || newIndex >= m_enabledDictIdList.size()) {
0276         return;
0277     }
0278 
0279     m_enabledDictModel->moveRows(QModelIndex(), oldIndex, 1, QModelIndex(), newIndex);
0280 
0281     m_enabledDictIdList.move(oldIndex, newIndex);
0282     Q_EMIT enabledDictsChanged();
0283 }
0284 
0285 bool DictionariesModel::loading() const
0286 {
0287     return m_loading;
0288 }
0289 
0290 QAbstractSocket::SocketError DictionariesModel::errorCode() const
0291 {
0292     return m_errorCode;
0293 }
0294 
0295 QString DictionariesModel::errorString() const
0296 {
0297     return m_errorString;
0298 }
0299 
0300 void DictionariesModel::slotDictErrorOccurred(QAbstractSocket::SocketError socketError, const QString &errorString)
0301 {
0302     m_errorCode = socketError;
0303     m_errorString = errorString;
0304 
0305     Q_EMIT errorCodeChanged();
0306     Q_EMIT errorStringChanged();
0307 }
0308 
0309 void DictionariesModel::slotDictLoadingChanged(bool loading)
0310 {
0311     m_loading = loading;
0312 
0313     Q_EMIT loadingChanged();
0314 }