File indexing completed on 2024-04-21 14:43:47

0001 /* GCompris - ActivityInfo.cpp
0002  *
0003  * SPDX-FileCopyrightText: 2014 Bruno Coudoin <bruno.coudoin@gcompris.net>
0004  *
0005  * Authors:
0006  *   Bruno Coudoin <bruno.coudoin@gcompris.net>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 #include "ActivityInfo.h"
0011 
0012 #include <QFile>
0013 #include <QtDebug>
0014 #include <QQmlProperty>
0015 #include <QQmlEngine>
0016 #include <QQmlComponent>
0017 
0018 #include "ApplicationSettings.h"
0019 
0020 ActivityInfo::ActivityInfo(QObject *parent) :
0021     QObject(parent),
0022     m_difficulty(0),
0023     m_minimalDifficulty(0),
0024     m_maximalDifficulty(0),
0025     m_favorite(false),
0026     m_enabled(true),
0027     m_createdInVersion(0)
0028 {
0029 }
0030 
0031 QString ActivityInfo::name() const
0032 {
0033     return m_name;
0034 }
0035 
0036 void ActivityInfo::setName(const QString &name)
0037 {
0038     m_name = name;
0039     // Once we are given a name, we can get the favorite property
0040     // from the persistant configuration
0041     m_favorite = ApplicationSettings::getInstance()->isFavorite(m_name);
0042 
0043     setCurrentLevels();
0044 
0045     Q_EMIT nameChanged();
0046 }
0047 
0048 QString ActivityInfo::section() const
0049 {
0050     return m_section;
0051 }
0052 void ActivityInfo::setSection(const QString &section)
0053 {
0054     m_section = section;
0055     Q_EMIT sectionChanged();
0056 }
0057 
0058 quint32 ActivityInfo::difficulty() const
0059 {
0060     return m_difficulty;
0061 }
0062 void ActivityInfo::setDifficulty(const quint32 &difficulty)
0063 {
0064     m_difficulty = difficulty;
0065     Q_EMIT difficultyChanged();
0066 }
0067 
0068 quint32 ActivityInfo::minimalDifficulty() const
0069 {
0070     return m_minimalDifficulty;
0071 }
0072 void ActivityInfo::setMinimalDifficulty(const quint32 &minimalDifficulty)
0073 {
0074     m_minimalDifficulty = minimalDifficulty;
0075     Q_EMIT minimalDifficultyChanged();
0076 }
0077 
0078 quint32 ActivityInfo::maximalDifficulty() const
0079 {
0080     return m_maximalDifficulty;
0081 }
0082 void ActivityInfo::setMaximalDifficulty(const quint32 &maximalDifficulty)
0083 {
0084     m_maximalDifficulty = maximalDifficulty;
0085     Q_EMIT maximalDifficultyChanged();
0086 }
0087 
0088 QString ActivityInfo::icon() const
0089 {
0090     return m_icon;
0091 }
0092 void ActivityInfo::setIcon(const QString &icon)
0093 {
0094     m_icon = icon;
0095     Q_EMIT iconChanged();
0096 }
0097 
0098 QString ActivityInfo::author() const
0099 {
0100     return m_author;
0101 }
0102 void ActivityInfo::setAuthor(const QString &author)
0103 {
0104     m_author = author;
0105     Q_EMIT authorChanged();
0106 }
0107 
0108 QString ActivityInfo::title() const
0109 {
0110     return m_title;
0111 }
0112 void ActivityInfo::setTitle(const QString &title)
0113 {
0114     m_title = title;
0115     Q_EMIT titleChanged();
0116 }
0117 
0118 QString ActivityInfo::description() const
0119 {
0120     return m_description;
0121 }
0122 void ActivityInfo::setDescription(const QString &description)
0123 {
0124     m_description = description;
0125     Q_EMIT descriptionChanged();
0126 }
0127 
0128 QString ActivityInfo::goal() const
0129 {
0130     return m_goal;
0131 }
0132 void ActivityInfo::setGoal(const QString &goal)
0133 {
0134     m_goal = goal;
0135     Q_EMIT goalChanged();
0136 }
0137 
0138 QString ActivityInfo::prerequisite() const
0139 {
0140     return m_prerequisite;
0141 }
0142 void ActivityInfo::setPrerequisite(const QString &prerequisite)
0143 {
0144     m_prerequisite = prerequisite;
0145     Q_EMIT prerequisiteChanged();
0146 }
0147 
0148 QString ActivityInfo::manual() const
0149 {
0150     return m_manual;
0151 }
0152 void ActivityInfo::setManual(const QString &manual)
0153 {
0154     m_manual = manual;
0155     Q_EMIT manualChanged();
0156 }
0157 
0158 QString ActivityInfo::credit() const
0159 {
0160     return m_credit;
0161 }
0162 void ActivityInfo::setCredit(const QString &credit)
0163 {
0164     m_credit = credit;
0165     Q_EMIT creditChanged();
0166 }
0167 
0168 bool ActivityInfo::favorite() const
0169 {
0170     return m_favorite;
0171 }
0172 void ActivityInfo::setFavorite(const bool favorite)
0173 {
0174     m_favorite = favorite;
0175     ApplicationSettings::getInstance()->setFavorite(m_name, m_favorite);
0176     Q_EMIT favoriteChanged();
0177 }
0178 
0179 bool ActivityInfo::enabled() const
0180 {
0181     return m_enabled;
0182 }
0183 void ActivityInfo::setEnabled(const bool enabled)
0184 {
0185     m_enabled = enabled;
0186     Q_EMIT enabledChanged();
0187 }
0188 
0189 int ActivityInfo::createdInVersion() const
0190 {
0191     return m_createdInVersion;
0192 }
0193 void ActivityInfo::setCreatedInVersion(const int created)
0194 {
0195     m_createdInVersion = created;
0196     Q_EMIT createdInVersionChanged();
0197 }
0198 
0199 QStringList ActivityInfo::levels() const
0200 {
0201     return m_levels;
0202 }
0203 
0204 void ActivityInfo::setLevels(const QStringList &levels)
0205 {
0206     // levels only contains one element containing all the difficulties
0207     m_levels = levels.front().split(',');
0208 
0209     setCurrentLevels();
0210 
0211     Q_EMIT levelsChanged();
0212 }
0213 
0214 void ActivityInfo::fillDatasets(QQmlEngine *engine)
0215 {
0216     quint32 levelMin = ApplicationSettings::getInstance()->filterLevelMin();
0217     quint32 levelMax = ApplicationSettings::getInstance()->filterLevelMax();
0218     for (const QString &level: qAsConst(m_levels)) {
0219         QString url = QString("qrc:/gcompris/src/activities/%1/resource/%2/Data.qml").arg(m_name.split('/')[0], level);
0220         QQmlComponent componentRoot(engine, QUrl(url));
0221         QObject *objectRoot = componentRoot.create();
0222         if (objectRoot != nullptr) {
0223             Dataset *dataset = qobject_cast<Dataset *>(objectRoot);
0224             if (levelMin > dataset->difficulty() || levelMax < dataset->difficulty()) {
0225                 dataset->setEnabled(false);
0226             }
0227 
0228             addDataset(level, dataset);
0229         }
0230         else {
0231             qDebug() << "ERROR: failed to load " << m_name << " " << componentRoot.errors();
0232         }
0233     }
0234     if (m_levels.empty()) {
0235         setMinimalDifficulty(m_difficulty);
0236         setMaximalDifficulty(m_difficulty);
0237     }
0238     else {
0239         computeMinMaxDifficulty();
0240     }
0241 }
0242 
0243 QStringList ActivityInfo::currentLevels() const
0244 {
0245     return m_currentLevels;
0246 }
0247 
0248 void ActivityInfo::computeMinMaxDifficulty()
0249 {
0250     if (m_currentLevels.empty() || m_datasets.empty()) {
0251         return;
0252     }
0253     quint32 minimalDifficultyFound = 100;
0254     quint32 maximalDifficultyFound = 0;
0255     for (const QString &datasetName: qAsConst(m_currentLevels)) {
0256         Dataset *data = getDataset(datasetName);
0257         if (minimalDifficultyFound > data->difficulty()) {
0258             minimalDifficultyFound = data->difficulty();
0259         }
0260         if (maximalDifficultyFound < data->difficulty()) {
0261             maximalDifficultyFound = data->difficulty();
0262         }
0263     }
0264     setMinimalDifficulty(minimalDifficultyFound);
0265     setMaximalDifficulty(maximalDifficultyFound);
0266 }
0267 
0268 void ActivityInfo::setCurrentLevels(const QStringList &currentLevels)
0269 {
0270     m_currentLevels = currentLevels;
0271     computeMinMaxDifficulty();
0272     Q_EMIT currentLevelsChanged();
0273 }
0274 
0275 void ActivityInfo::setCurrentLevels()
0276 {
0277     if (!m_name.isEmpty()) {
0278         // by default, activate all existing levels
0279         if (!m_levels.empty() && ApplicationSettings::getInstance()->currentLevels(m_name).empty()) {
0280             ApplicationSettings::getInstance()->setCurrentLevels(m_name, m_levels);
0281         }
0282         m_currentLevels = ApplicationSettings::getInstance()->currentLevels(m_name);
0283     }
0284     // Remove levels that could have been added in the configuration but are not existing
0285     // Either we rename a dataset, or after working in another branch to add dataset and switching to a branch without it
0286     QStringList levelsToRemove;
0287     for (const QString &level: qAsConst(m_currentLevels)) {
0288         if (!m_levels.contains(level)) {
0289             qDebug() << QString("Invalid level %1 for activity %2, removing it").arg(level, m_name);
0290             levelsToRemove << level;
0291         }
0292     }
0293     for (const QString &level: qAsConst(levelsToRemove)) {
0294         m_currentLevels.removeOne(level);
0295     }
0296     computeMinMaxDifficulty();
0297 }
0298 
0299 void ActivityInfo::enableDatasetsBetweenDifficulties(quint32 levelMin, quint32 levelMax)
0300 {
0301     QStringList newLevels;
0302     for (auto it = m_datasets.begin(); it != m_datasets.end(); ++it) {
0303         Dataset *dataset = it.value();
0304         if (levelMin <= dataset->difficulty() && dataset->difficulty() <= levelMax) {
0305             newLevels << it.key();
0306             dataset->setEnabled(true);
0307         }
0308         else {
0309             dataset->setEnabled(false);
0310         }
0311     }
0312     setCurrentLevels(newLevels);
0313     ApplicationSettings::getInstance()->setCurrentLevels(m_name, m_currentLevels, false);
0314 }
0315 
0316 void ActivityInfo::addDataset(const QString &name, Dataset *dataset)
0317 {
0318     m_datasets[name] = dataset;
0319 }
0320 
0321 Dataset *ActivityInfo::getDataset(const QString &name) const
0322 {
0323     return m_datasets[name];
0324 }
0325 
0326 bool ActivityInfo::hasConfig() const
0327 {
0328     return QFile::exists(":/gcompris/src/activities/" + m_name.split('/')[0] + "/ActivityConfig.qml");
0329 }
0330 
0331 bool ActivityInfo::hasDataset() const
0332 {
0333     return !m_levels.empty();
0334 }
0335 
0336 void ActivityInfo::resetLevels()
0337 {
0338     enableDatasetsBetweenDifficulties(1, 6);
0339 }
0340 
0341 #include "moc_ActivityInfo.cpp"