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 }