1 /*
2  * SPDX-FileCopyrightText: 2007 Jeremy Whiting <jpwhiting@kde.org>
3  * SPDX-FileCopyrightText: 2007 Frederik Gladhorn <frederik.gladhorn@kdemail.net>
4  * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "keduvoccontainer.h"
8 
9 #include "keduvocdocument.h"
10 #include "keduvocexpression.h"
11 
12 #include <QDebug>
13 
14 /** private class to store information about a lesson */
15 class KEduVocContainer::Private
16 {
17 public:
18     ~Private();
19 
20     // properties for this lesson
21     QString m_name;
22     bool m_inPractice;
23 
24     // The containing document.  This is only set for the top lesson, so to
25     // get to the document, you need to follow the parent pointer to the top
26     // container.
27     KEduVocDocument *m_document;
28 
29     // other lessons in the tree
30     KEduVocContainer *m_parentContainer;
31     QList < KEduVocContainer * > m_childContainers;
32 
33     EnumContainerType m_type;
34 
35     QList < KEduVocExpression* > m_childLessonEntries;
36     bool m_childLessonEntriesValid;
37 
38     /// Image url
39     QUrl m_imageUrl;
40 };
41 
~Private()42 KEduVocContainer::Private::~Private()
43 {
44     qDeleteAll(m_childContainers);
45 }
46 
47 
48 // This is a private constructor only used by KEduVocDocument when creating
49 // the top level lesson.
KEduVocContainer(const QString & name,EnumContainerType type,KEduVocDocument * document)50 KEduVocContainer::KEduVocContainer(const QString& name, EnumContainerType type,
51 				   KEduVocDocument *document)
52         : d( new Private )
53 {
54     d->m_parentContainer = 0;
55     d->m_name = name;
56     d->m_inPractice = true;
57     d->m_type = type;
58     d->m_childLessonEntriesValid = false;
59 
60     d->m_document = document;
61 }
62 
63 
KEduVocContainer(const QString & name,EnumContainerType type,KEduVocContainer * parent)64 KEduVocContainer::KEduVocContainer(const QString& name, EnumContainerType type, KEduVocContainer *parent)
65         : d( new Private )
66 {
67     d->m_parentContainer = parent;
68     d->m_name = name;
69     d->m_inPractice = true;
70     d->m_type = type;
71     d->m_childLessonEntriesValid = false;
72 
73     d->m_document = 0;
74 }
75 
KEduVocContainer(const KEduVocContainer & other)76 KEduVocContainer::KEduVocContainer( const KEduVocContainer &other )
77         : d( new Private )
78 {
79     d->m_name = other.d->m_name;
80     d->m_inPractice = other.d->m_inPractice;
81     d->m_type = other.d->m_type;
82     d->m_parentContainer = other.d->m_parentContainer;
83     d->m_childLessonEntriesValid = false;
84 }
85 
~KEduVocContainer()86 KEduVocContainer::~KEduVocContainer()
87 {
88     delete d;
89 }
90 
document() const91 KEduVocDocument *KEduVocContainer::document() const
92 {
93     KEduVocContainer *cont = (KEduVocContainer *)this;
94     while (cont->d->m_parentContainer) {
95 	cont = cont->d->m_parentContainer;
96     }
97 
98     Q_ASSERT(cont->d->m_document);
99     return cont->d->m_document;
100 }
101 
appendChildContainer(KEduVocContainer * child)102 void KEduVocContainer::appendChildContainer(KEduVocContainer * child)
103 {
104     d->m_childContainers.append(child);
105     child->d->m_parentContainer = this;
106 
107     invalidateChildLessonEntries();
108 }
109 
childContainer(int row)110 KEduVocContainer * KEduVocContainer::childContainer(int row)
111 {
112     return d->m_childContainers.value(row);
113 }
114 
115 
childContainer(const QString & name)116 KEduVocContainer * KEduVocContainer::childContainer(const QString & name)
117 {
118     if (d->m_name == name) {
119         return this;
120     }
121 
122     foreach (KEduVocContainer *container, d->m_childContainers) {
123         KEduVocContainer *found = container->childContainer(name);
124         if (found) {
125             return found;
126         }
127     }
128     return 0;
129 }
130 
131 
deleteChildContainer(int row)132 void KEduVocContainer::deleteChildContainer(int row)
133 {
134     qDebug() << "Delete of container - check entry deletion!";
135     delete d->m_childContainers.takeAt(row);
136 
137     invalidateChildLessonEntries();
138 }
139 
removeChildContainer(int row)140 void KEduVocContainer::removeChildContainer(int row)
141 {
142     d->m_childContainers.removeAt(row);
143     invalidateChildLessonEntries();
144 }
145 
146 
childContainerCount() const147 int KEduVocContainer::childContainerCount() const
148 {
149     return d->m_childContainers.count();
150 }
151 
row() const152 int KEduVocContainer::row() const
153 {
154     if (d->m_parentContainer) {
155         return d->m_parentContainer->d->m_childContainers.indexOf(const_cast<KEduVocContainer*>(this));
156     }
157     return 0;
158 }
159 
160 
operator =(const KEduVocContainer & other)161 KEduVocContainer& KEduVocContainer::operator= ( const KEduVocContainer &other )
162 {
163     d->m_name = other.d->m_name;
164     d->m_inPractice = other.d->m_inPractice;
165     return *this;
166 }
167 
operator ==(const KEduVocContainer & other) const168 bool KEduVocContainer::operator==(const KEduVocContainer &other) const
169 {
170     return  d->m_name == other.d->m_name &&
171             d->m_inPractice == other.d->m_inPractice
172 /// @todo make this return something useful
173             ;
174 }
175 
setName(const QString & name)176 void KEduVocContainer::setName( const QString &name )
177 {
178     d->m_name = name;
179 }
180 
name()181 QString KEduVocContainer::name()
182 {
183     return d->m_name;
184 }
185 
inPractice()186 bool KEduVocContainer::inPractice()
187 {
188     return d->m_inPractice;
189 }
190 
setInPractice(bool inPractice)191 void KEduVocContainer::setInPractice(bool inPractice)
192 {
193     d->m_inPractice = inPractice;
194 }
195 
removeTranslation(int translation)196 void KEduVocContainer::removeTranslation(int translation)
197 {
198     foreach(KEduVocContainer *childContainer, d->m_childContainers) {
199         childContainer->removeTranslation(translation);
200     }
201 
202     foreach(KEduVocExpression *entry, entries() ) {
203         entry->removeTranslation( translation );
204     }
205 }
206 
entriesRecursive()207 QList< KEduVocExpression * > KEduVocContainer::entriesRecursive()
208 {
209     if (!d->m_childLessonEntriesValid) {
210         updateChildLessonEntries();
211     }
212     return d->m_childLessonEntries;
213 }
214 
childContainers()215 QList< KEduVocContainer * > KEduVocContainer::childContainers()
216 {
217     return d->m_childContainers;
218 }
219 
parent()220 KEduVocContainer * KEduVocContainer::parent()
221 {
222     return d->m_parentContainer;
223 }
224 
setContainerType(KEduVocContainer::EnumContainerType type)225 void KEduVocContainer::setContainerType(KEduVocContainer::EnumContainerType type)
226 {
227     d->m_type = type;
228 }
229 
containerType()230 KEduVocContainer::EnumContainerType KEduVocContainer::containerType()
231 {
232     return d->m_type;
233 }
234 
235 
imageUrl()236 QUrl KEduVocContainer::imageUrl()
237 {
238     return d->m_imageUrl;
239 }
240 
setImageUrl(const QUrl & url)241 void KEduVocContainer::setImageUrl(const QUrl &url)
242 {
243     d->m_imageUrl = url;
244 }
245 
insertChildContainer(int row,KEduVocContainer * child)246 void KEduVocContainer::insertChildContainer(int row, KEduVocContainer * child)
247 {
248     d->m_childContainers.insert(row, child);
249     child->d->m_parentContainer = this;
250 
251     invalidateChildLessonEntries();
252 }
253 
updateChildLessonEntries()254 void KEduVocContainer::updateChildLessonEntries()
255 {
256     QList < KEduVocExpression* > entriesRecursive = entries();
257 
258     foreach(KEduVocContainer *childContainer, d->m_childContainers)
259         foreach(KEduVocExpression * expr, childContainer->entries(Recursive))
260             entriesRecursive.append(expr);
261 
262     d->m_childLessonEntries = entriesRecursive;
263     d->m_childLessonEntriesValid = true;
264 }
265 
invalidateChildLessonEntries()266 void KEduVocContainer::invalidateChildLessonEntries()
267 {
268     d->m_childLessonEntriesValid = false;
269     // propagate to parent
270     if (d->m_parentContainer) {
271         d->m_parentContainer->invalidateChildLessonEntries();
272     }
273 }
274 
averageGrade(int translation,EnumEntriesRecursive recursive)275 double KEduVocContainer::averageGrade(int translation, EnumEntriesRecursive recursive)
276 {
277     int sum = 0,  presum = 0,  count = 0;
278     foreach (KEduVocExpression *entry, entries(recursive)) {
279         KEduVocTranslation & trans( *entry->translation(translation) );
280         if ( !trans.isEmpty() ) {
281             ++count;
282             sum += trans.grade();
283             presum += trans.preGrade();
284         }
285     }
286     // make that a percentage
287     // There are KV_MAX_GRADE grades from 0 -> 100 %
288     // There are KV_MAX_GRADE preGrades within the first grade.
289     if (count == 0) {
290         return 100.0;
291     }
292     return ((sum * 100.0 / KV_MAX_GRADE) + (presum * 100.0 / (KV_MAX_GRADE * KV_MAX_GRADE))) / count;
293 }
294 
expressionsOfGrade(int translation,grade_t grade,EnumEntriesRecursive recursive)295 int KEduVocContainer::expressionsOfGrade(int translation, grade_t grade, EnumEntriesRecursive recursive)
296 {
297     int sum = 0;
298     foreach (KEduVocExpression *entry, entries(recursive)) {
299         if (entry->translation(translation)->grade() == grade) {
300             sum++;
301         }
302     }
303     return sum;
304 }
305 
resetGrades(int translation,EnumEntriesRecursive recursive)306 void KEduVocContainer::resetGrades(int translation, EnumEntriesRecursive recursive)
307 {
308     foreach (KEduVocExpression *entry, entries(recursive)) {
309         entry->resetGrades(translation);
310     }
311 
312     document()->setModified(true);
313 }
314