File indexing completed on 2024-04-14 03:46:38

0001 /*
0002  * SPDX-FileCopyrightText: 2007 Jeremy Whiting <jpwhiting@kde.org>
0003  * SPDX-FileCopyrightText: 2007 Frederik Gladhorn <frederik.gladhorn@kdemail.net>
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "keduvoccontainer.h"
0008 
0009 #include "keduvocdocument.h"
0010 #include "keduvocexpression.h"
0011 
0012 #include <QDebug>
0013 
0014 /** private class to store information about a lesson */
0015 class KEduVocContainer::Private
0016 {
0017 public:
0018     ~Private();
0019 
0020     // properties for this lesson
0021     QString m_name;
0022     bool m_inPractice;
0023 
0024     // The containing document.  This is only set for the top lesson, so to
0025     // get to the document, you need to follow the parent pointer to the top
0026     // container.
0027     KEduVocDocument *m_document;
0028 
0029     // other lessons in the tree
0030     KEduVocContainer *m_parentContainer;
0031     QList<KEduVocContainer *> m_childContainers;
0032 
0033     EnumContainerType m_type;
0034 
0035     QList<KEduVocExpression *> m_childLessonEntries;
0036     bool m_childLessonEntriesValid;
0037 
0038     /// Image url
0039     QUrl m_imageUrl;
0040 };
0041 
0042 KEduVocContainer::Private::~Private()
0043 {
0044     qDeleteAll(m_childContainers);
0045 }
0046 
0047 // This is a private constructor only used by KEduVocDocument when creating
0048 // the top level lesson.
0049 KEduVocContainer::KEduVocContainer(const QString &name, EnumContainerType type, KEduVocDocument *document)
0050     : d(new Private)
0051 {
0052     d->m_parentContainer = nullptr;
0053     d->m_name = name;
0054     d->m_inPractice = true;
0055     d->m_type = type;
0056     d->m_childLessonEntriesValid = false;
0057 
0058     d->m_document = document;
0059 }
0060 
0061 KEduVocContainer::KEduVocContainer(const QString &name, EnumContainerType type, KEduVocContainer *parent)
0062     : d(new Private)
0063 {
0064     d->m_parentContainer = parent;
0065     d->m_name = name;
0066     d->m_inPractice = true;
0067     d->m_type = type;
0068     d->m_childLessonEntriesValid = false;
0069 
0070     d->m_document = nullptr;
0071 }
0072 
0073 KEduVocContainer::KEduVocContainer(const KEduVocContainer &other)
0074     : d(new Private)
0075 {
0076     d->m_name = other.d->m_name;
0077     d->m_inPractice = other.d->m_inPractice;
0078     d->m_type = other.d->m_type;
0079     d->m_parentContainer = other.d->m_parentContainer;
0080     d->m_childLessonEntriesValid = false;
0081 }
0082 
0083 KEduVocContainer::~KEduVocContainer()
0084 {
0085     delete d;
0086 }
0087 
0088 KEduVocDocument *KEduVocContainer::document() const
0089 {
0090     KEduVocContainer *cont = (KEduVocContainer *)this;
0091     while (cont->d->m_parentContainer) {
0092         cont = cont->d->m_parentContainer;
0093     }
0094 
0095     Q_ASSERT(cont->d->m_document);
0096     return cont->d->m_document;
0097 }
0098 
0099 void KEduVocContainer::appendChildContainer(KEduVocContainer *child)
0100 {
0101     d->m_childContainers.append(child);
0102     child->d->m_parentContainer = this;
0103 
0104     invalidateChildLessonEntries();
0105 }
0106 
0107 KEduVocContainer *KEduVocContainer::childContainer(int row)
0108 {
0109     return d->m_childContainers.value(row);
0110 }
0111 
0112 KEduVocContainer *KEduVocContainer::childContainer(const QString &name)
0113 {
0114     if (d->m_name == name) {
0115         return this;
0116     }
0117 
0118     foreach (KEduVocContainer *container, d->m_childContainers) {
0119         KEduVocContainer *found = container->childContainer(name);
0120         if (found) {
0121             return found;
0122         }
0123     }
0124     return nullptr;
0125 }
0126 
0127 void KEduVocContainer::deleteChildContainer(int row)
0128 {
0129     qDebug() << "Delete of container - check entry deletion!";
0130     delete d->m_childContainers.takeAt(row);
0131 
0132     invalidateChildLessonEntries();
0133 }
0134 
0135 void KEduVocContainer::removeChildContainer(int row)
0136 {
0137     d->m_childContainers.removeAt(row);
0138     invalidateChildLessonEntries();
0139 }
0140 
0141 int KEduVocContainer::childContainerCount() const
0142 {
0143     return d->m_childContainers.count();
0144 }
0145 
0146 int KEduVocContainer::row() const
0147 {
0148     if (d->m_parentContainer) {
0149         return d->m_parentContainer->d->m_childContainers.indexOf(const_cast<KEduVocContainer *>(this));
0150     }
0151     return 0;
0152 }
0153 
0154 KEduVocContainer &KEduVocContainer::operator=(const KEduVocContainer &other)
0155 {
0156     d->m_name = other.d->m_name;
0157     d->m_inPractice = other.d->m_inPractice;
0158     return *this;
0159 }
0160 
0161 bool KEduVocContainer::operator==(const KEduVocContainer &other) const
0162 {
0163     return d->m_name == other.d->m_name && d->m_inPractice == other.d->m_inPractice
0164         /// @todo make this return something useful
0165         ;
0166 }
0167 
0168 void KEduVocContainer::setName(const QString &name)
0169 {
0170     d->m_name = name;
0171 }
0172 
0173 QString KEduVocContainer::name()
0174 {
0175     return d->m_name;
0176 }
0177 
0178 bool KEduVocContainer::inPractice()
0179 {
0180     return d->m_inPractice;
0181 }
0182 
0183 void KEduVocContainer::setInPractice(bool inPractice)
0184 {
0185     d->m_inPractice = inPractice;
0186 }
0187 
0188 void KEduVocContainer::removeTranslation(int translation)
0189 {
0190     foreach (KEduVocContainer *childContainer, d->m_childContainers) {
0191         childContainer->removeTranslation(translation);
0192     }
0193 
0194     foreach (KEduVocExpression *entry, entries()) {
0195         entry->removeTranslation(translation);
0196     }
0197 }
0198 
0199 QList<KEduVocExpression *> KEduVocContainer::entriesRecursive()
0200 {
0201     if (!d->m_childLessonEntriesValid) {
0202         updateChildLessonEntries();
0203     }
0204     return d->m_childLessonEntries;
0205 }
0206 
0207 QList<KEduVocContainer *> KEduVocContainer::childContainers()
0208 {
0209     return d->m_childContainers;
0210 }
0211 
0212 KEduVocContainer *KEduVocContainer::parent()
0213 {
0214     return d->m_parentContainer;
0215 }
0216 
0217 void KEduVocContainer::setContainerType(KEduVocContainer::EnumContainerType type)
0218 {
0219     d->m_type = type;
0220 }
0221 
0222 KEduVocContainer::EnumContainerType KEduVocContainer::containerType()
0223 {
0224     return d->m_type;
0225 }
0226 
0227 QUrl KEduVocContainer::imageUrl()
0228 {
0229     return d->m_imageUrl;
0230 }
0231 
0232 void KEduVocContainer::setImageUrl(const QUrl &url)
0233 {
0234     d->m_imageUrl = url;
0235 }
0236 
0237 void KEduVocContainer::insertChildContainer(int row, KEduVocContainer *child)
0238 {
0239     d->m_childContainers.insert(row, child);
0240     child->d->m_parentContainer = this;
0241 
0242     invalidateChildLessonEntries();
0243 }
0244 
0245 void KEduVocContainer::updateChildLessonEntries()
0246 {
0247     QList<KEduVocExpression *> entriesRecursive = entries();
0248 
0249     foreach (KEduVocContainer *childContainer, d->m_childContainers)
0250         foreach (KEduVocExpression *expr, childContainer->entries(Recursive))
0251             entriesRecursive.append(expr);
0252 
0253     d->m_childLessonEntries = entriesRecursive;
0254     d->m_childLessonEntriesValid = true;
0255 }
0256 
0257 void KEduVocContainer::invalidateChildLessonEntries()
0258 {
0259     d->m_childLessonEntriesValid = false;
0260     // propagate to parent
0261     if (d->m_parentContainer) {
0262         d->m_parentContainer->invalidateChildLessonEntries();
0263     }
0264 }
0265 
0266 double KEduVocContainer::averageGrade(int translation, EnumEntriesRecursive recursive)
0267 {
0268     int sum = 0, presum = 0, count = 0;
0269     foreach (KEduVocExpression *entry, entries(recursive)) {
0270         KEduVocTranslation &trans(*entry->translation(translation));
0271         if (!trans.isEmpty()) {
0272             ++count;
0273             sum += trans.grade();
0274             presum += trans.preGrade();
0275         }
0276     }
0277     // make that a percentage
0278     // There are KV_MAX_GRADE grades from 0 -> 100 %
0279     // There are KV_MAX_GRADE preGrades within the first grade.
0280     if (count == 0) {
0281         return 100.0;
0282     }
0283     return ((sum * 100.0 / KV_MAX_GRADE) + (presum * 100.0 / (KV_MAX_GRADE * KV_MAX_GRADE))) / count;
0284 }
0285 
0286 int KEduVocContainer::expressionsOfGrade(int translation, grade_t grade, EnumEntriesRecursive recursive)
0287 {
0288     int sum = 0;
0289     foreach (KEduVocExpression *entry, entries(recursive)) {
0290         if (entry->translation(translation)->grade() == grade) {
0291             sum++;
0292         }
0293     }
0294     return sum;
0295 }
0296 
0297 void KEduVocContainer::resetGrades(int translation, EnumEntriesRecursive recursive)
0298 {
0299     foreach (KEduVocExpression *entry, entries(recursive)) {
0300         entry->resetGrades(translation);
0301     }
0302 
0303     document()->setModified(true);
0304 }