File indexing completed on 2024-10-06 03:31:31
0001 // SPDX-FileCopyrightText: 2006-2010 Peter Hedlund <peter.hedlund@kdemail.net> 0002 // SPDX-FileCopyrightText: 2023 Carl Schwan <carl@carlschwan.eu> 0003 // SPDX-License-Identifier: GPL-2.0-or-later 0004 0005 #include "kwqcardmodel.h" 0006 #include "keduvocexpression.h" 0007 #include "kwordquiz_version.h" 0008 #include <keduvocdocument.h> 0009 #include <keduvoclesson.h> 0010 0011 #include <KLocalizedString> 0012 #include <QDebug> 0013 #include <QDir> 0014 #include <QFileDialog> 0015 #include <QPointer> 0016 #include <QRegularExpression> 0017 #include <QStandardPaths> 0018 0019 using namespace Qt::Literals::StringLiterals; 0020 0021 KWQCardModel::KWQCardModel(QObject *parent) 0022 : QAbstractListModel(parent) 0023 { 0024 } 0025 0026 void KWQCardModel::createNew() 0027 { 0028 auto doc = new KEduVocDocument(this); 0029 doc->setGenerator(QStringLiteral("kwordquiz %1").arg(QStringLiteral(KWORDQUIZ_VERSION_STRING))); 0030 doc->appendIdentifier(); 0031 doc->identifier(0).setName(i18n("Question")); 0032 doc->appendIdentifier(); 0033 doc->identifier(1).setName(i18n("Answer")); 0034 0035 setDocument(doc); 0036 } 0037 0038 QString KWQCardModel::identifierLeft() const 0039 { 0040 return m_document ? m_document->identifier(0).name() : QString(); 0041 } 0042 0043 void KWQCardModel::setIdentifierLeft(const QString &identifierLeft) 0044 { 0045 if (m_document->identifier(0).name() == identifierLeft) { 0046 return; 0047 } 0048 m_document->identifier(0).setName(identifierLeft); 0049 identifierLeftChanged(); 0050 } 0051 0052 QString KWQCardModel::identifierRight() const 0053 { 0054 return m_document ? m_document->identifier(1).name() : QString(); 0055 } 0056 0057 void KWQCardModel::setIdentifierRight(const QString &identifierRight) 0058 { 0059 if (m_document->identifier(1).name() == identifierRight) { 0060 return; 0061 } 0062 m_document->identifier(1).setName(identifierRight); 0063 identifierRightChanged(); 0064 } 0065 0066 void KWQCardModel::add(const QString &question, const QString &answer) 0067 { 0068 Q_ASSERT(m_document); 0069 0070 beginInsertRows({}, rowCount(), rowCount()); 0071 m_document->lesson()->appendEntry(new KEduVocExpression({ question, answer })); 0072 endInsertRows(); 0073 0074 Q_EMIT multipleChoiceAvailableChanged(); 0075 0076 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(rowCount() - 1); 0077 expression->setTranslation(0, question); 0078 expression->setTranslation(1, answer); 0079 0080 Q_EMIT dataChanged(index(rowCount() - 1, 0), index(rowCount() - 1, 0)); 0081 } 0082 0083 void KWQCardModel::edit(const int row, const QString &question, const QString &answer) 0084 { 0085 Q_ASSERT(m_document); 0086 0087 if (question.length() == 0 && answer.length() == 0 && row != 0 && row != rowCount() - 1) { 0088 beginRemoveRows({}, row, row); 0089 const auto entry = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0090 entry->lesson()->removeEntry(entry); 0091 endRemoveRows(); 0092 0093 Q_EMIT multipleChoiceAvailableChanged(); 0094 delete entry; 0095 0096 return; 0097 } 0098 0099 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0100 expression->setTranslation(0, question); 0101 expression->setTranslation(1, answer); 0102 0103 Q_EMIT dataChanged(index(row, 0), index(row, 0)); 0104 } 0105 0106 bool KWQCardModel::save() 0107 { 0108 Q_ASSERT(m_document); 0109 0110 QUrl url; 0111 0112 if (m_document->url().isEmpty()) { 0113 const auto dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0114 url = QUrl::fromLocalFile(QDir::toNativeSeparators(dir + QLatin1Char('/') + m_document->title() + QStringLiteral(".kvtml"))); 0115 0116 // Create parent in case it doesn't exist 0117 QDir newDir(dir); 0118 if (!newDir.mkpath(dir)) { 0119 qCritical() << "Unable to create directory" << dir; 0120 return false; 0121 } 0122 } else { 0123 url = m_document->url(); 0124 } 0125 0126 0127 auto result = m_document->saveAs(url, KEduVocDocument::Automatic); 0128 return result == KEduVocDocument::NoError; 0129 } 0130 0131 KEduVocDocument *KWQCardModel::document() const 0132 { 0133 return m_document; 0134 } 0135 0136 void KWQCardModel::setDocument(KEduVocDocument *document) 0137 { 0138 if (document == m_document) { 0139 return; 0140 } 0141 beginResetModel(); 0142 m_document = document; 0143 endResetModel(); 0144 0145 Q_EMIT documentChanged(); 0146 Q_EMIT enabledChanged(); 0147 Q_EMIT titleChanged(); 0148 Q_EMIT authorContact(); 0149 Q_EMIT authorContactChanged(); 0150 Q_EMIT licenseChanged(); 0151 Q_EMIT identifierLeftChanged(); 0152 Q_EMIT identifierRightChanged(); 0153 } 0154 0155 QString KWQCardModel::title() const 0156 { 0157 return m_document ? m_document->title() : QString{}; 0158 } 0159 0160 void KWQCardModel::setTitle(const QString &title) 0161 { 0162 Q_ASSERT(m_document); 0163 0164 if (title == m_document->title()) { 0165 return; 0166 } 0167 m_document->setTitle(title); 0168 0169 Q_EMIT titleChanged(); 0170 } 0171 0172 QString KWQCardModel::author() const 0173 { 0174 return m_document ? m_document->author() : QString{}; 0175 } 0176 0177 void KWQCardModel::setAuthor(const QString &author) 0178 { 0179 Q_ASSERT(m_document); 0180 0181 if (author == m_document->author()) { 0182 return; 0183 } 0184 m_document->setAuthor(author); 0185 Q_EMIT authorChanged(); 0186 } 0187 0188 QString KWQCardModel::authorContact() const 0189 { 0190 return m_document ? m_document->authorContact() : QString{}; 0191 } 0192 0193 void KWQCardModel::setAuthorContact(const QString &authorContact) 0194 { 0195 Q_ASSERT(m_document); 0196 0197 if (authorContact == m_document->authorContact()) { 0198 return; 0199 } 0200 m_document->setAuthorContact(authorContact); 0201 Q_EMIT authorContactChanged(); 0202 } 0203 0204 QString KWQCardModel::license() const 0205 { 0206 return m_document ? m_document->license() : QString{}; 0207 } 0208 0209 void KWQCardModel::setLicense(const QString &license) 0210 { 0211 Q_ASSERT(m_document); 0212 0213 if (license == m_document->license()) { 0214 return; 0215 } 0216 m_document->setLicense(license); 0217 Q_EMIT licenseChanged(); 0218 } 0219 0220 QString KWQCardModel::langQuestion() const 0221 { 0222 return m_document ? m_document->identifier(0).locale() : QString{}; 0223 } 0224 0225 void KWQCardModel::setLangQuestion(const QString &langQuestion) 0226 { 0227 Q_ASSERT(m_document); 0228 0229 if (langQuestion == m_document->identifier(0).locale()) { 0230 return; 0231 } 0232 auto identifier = m_document->identifier(0); 0233 identifier.setLocale(langQuestion); 0234 m_document->setIdentifier(0, identifier); 0235 Q_EMIT langQuestionChanged(); 0236 } 0237 0238 QString KWQCardModel::langAnswer() const 0239 { 0240 return m_document ? m_document->identifier(1).locale() : QString{}; 0241 } 0242 0243 void KWQCardModel::setLangAnswer(const QString &langAnswer) 0244 { 0245 Q_ASSERT(m_document); 0246 0247 if (langAnswer == m_document->identifier(1).locale()) { 0248 return; 0249 } 0250 auto identifier = m_document->identifier(1); 0251 identifier.setLocale(langAnswer); 0252 m_document->setIdentifier(1, identifier); 0253 Q_EMIT langAnswerChanged(); 0254 } 0255 0256 bool KWQCardModel::multipleChoiceAvailable() const 0257 { 0258 return rowCount() > 4; 0259 } 0260 0261 bool KWQCardModel::enabled() const 0262 { 0263 return m_document; 0264 } 0265 0266 void KWQCardModel::addQuestionImage(const int row, const QUrl &url) 0267 { 0268 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0269 expression->translation(0)->setImageUrl(url); 0270 0271 Q_EMIT dataChanged(index(row, 0), index(row, 0), {QuestionImageRole}); 0272 } 0273 0274 void KWQCardModel::addAnswerImage(const int row, const QUrl &url) 0275 { 0276 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0277 expression->translation(1)->setImageUrl(url); 0278 0279 Q_EMIT dataChanged(index(row, 0), index(row, 0), {AnswerImageRole}); 0280 } 0281 0282 void KWQCardModel::removeQuestionImage(const int row) 0283 { 0284 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0285 expression->translation(0)->setImageUrl({}); 0286 0287 Q_EMIT dataChanged(index(row, 0), index(row, 0), {QuestionImageRole}); 0288 } 0289 0290 void KWQCardModel::removeAnswerImage(const int row) 0291 { 0292 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0293 expression->translation(1)->setImageUrl({}); 0294 0295 Q_EMIT dataChanged(index(row, 0), index(row, 0), {AnswerImageRole}); 0296 } 0297 0298 void KWQCardModel::addQuestionSound(const int row, const QUrl &url) 0299 { 0300 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0301 expression->translation(0)->setSoundUrl(url); 0302 0303 Q_EMIT dataChanged(index(row, 0), index(row, 0), {QuestionSoundRole}); 0304 } 0305 0306 void KWQCardModel::addAnswerSound(const int row, const QUrl &url) 0307 { 0308 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0309 expression->translation(1)->setSoundUrl(url); 0310 0311 Q_EMIT dataChanged(index(row, 0), index(row, 0), {AnswerSoundRole}); 0312 } 0313 0314 void KWQCardModel::removeQuestionSound(const int row) 0315 { 0316 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0317 expression->translation(0)->setSoundUrl({}); 0318 0319 Q_EMIT dataChanged(index(row, 0), index(row, 0), {QuestionSoundRole}); 0320 } 0321 0322 void KWQCardModel::removeAnswerSound(const int row) 0323 { 0324 auto expression = m_document->lesson()->entries(KEduVocLesson::Recursive).value(row); 0325 expression->translation(1)->setSoundUrl({}); 0326 0327 Q_EMIT dataChanged(index(row, 0), index(row, 0), {AnswerSoundRole}); 0328 } 0329 0330 int KWQCardModel::rowCount(const QModelIndex &parent) const 0331 { 0332 if (parent.isValid() || !m_document) { 0333 return 0; 0334 } 0335 0336 return m_document->lesson()->entryCount(KEduVocLesson::Recursive); 0337 } 0338 0339 QVariant KWQCardModel::data(const QModelIndex &index, int role) const 0340 { 0341 Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)); 0342 0343 const auto entry = m_document->lesson()->entries(KEduVocLesson::Recursive).value(index.row()); 0344 0345 switch (role) { 0346 case Qt::DisplayRole: 0347 return QString(entry->translation(0)->text() + u" ->"_s + entry->translation(1)->text()); 0348 0349 case QuestionRole: 0350 return entry->translation(0)->text(); 0351 case QuestionImageRole: 0352 return entry->translation(0)->imageUrl().toLocalFile(); 0353 case QuestionSoundRole: 0354 return entry->translation(0)->soundUrl().toLocalFile(); 0355 0356 case AnswerRole: 0357 return entry->translation(1)->text(); 0358 case AnswerImageRole: 0359 return entry->translation(1)->imageUrl().toLocalFile(); 0360 case AnswerSoundRole: 0361 return entry->translation(1)->soundUrl().toLocalFile(); 0362 0363 default: 0364 return {}; 0365 } 0366 } 0367 0368 QHash<int, QByteArray> KWQCardModel::roleNames() const 0369 { 0370 return { 0371 { QuestionRole, "question" }, 0372 { QuestionImageRole, "questionImage" }, 0373 { QuestionSoundRole, "questionSound" }, 0374 0375 { AnswerRole, "answer" }, 0376 { AnswerImageRole, "answerImage" }, 0377 { AnswerSoundRole, "answerSound" }, 0378 }; 0379 } 0380 0381 #include "moc_kwqcardmodel.cpp"