1 /*
2     SPDX-FileCopyrightText: 2013-2016 Andreas Cord-Landwehr <cordlandwehr@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "learner.h"
8 #include "learner_p.h"
9 #include "liblearner_debug.h"
10 #include <QDir>
11 #include <QFileInfo>
12 #include <QHash>
13 #include <QPixmap>
14 
15 using namespace LearnerProfile;
16 
Learner(QObject * parent)17 Learner::Learner(QObject *parent)
18     : QObject(parent)
19     , d(new LearnerPrivate)
20 {
21     connect(this, &Learner::goalAdded, this, &Learner::goalCountChanged);
22     connect(this, &Learner::goalRemoved, this, &Learner::goalCountChanged);
23 }
24 
~Learner()25 Learner::~Learner()
26 {
27 }
28 
name() const29 QString Learner::name() const
30 {
31     return d->m_name;
32 }
33 
setName(const QString & name)34 void Learner::setName(const QString &name)
35 {
36     if (name == d->m_name) {
37         return;
38     }
39     d->m_name = name;
40     emit nameChanged();
41 }
42 
identifier() const43 int Learner::identifier() const
44 {
45     return d->m_identifier;
46 }
47 
setIdentifier(int identifier)48 void Learner::setIdentifier(int identifier)
49 {
50     if (identifier == d->m_identifier) {
51         return;
52     }
53     d->m_identifier = identifier;
54     emit identifierChanged();
55 }
56 
imageUrl() const57 QString Learner::imageUrl() const
58 {
59     QString path = d->imagePath();
60     if (!QFileInfo::exists(path)) {
61         return QString();
62     }
63     return "file://" + path;
64 }
65 
clearImage()66 void Learner::clearImage()
67 {
68     const QString path {d->imagePath()};
69     if (!QFileInfo::exists(path)) {
70         return;
71     }
72     QFile file;
73     if (!file.remove(path)) {
74         qCCritical(LIBLEARNER_LOG) << "could not remove image:" << path;
75     }
76     emit imageChanged();
77 }
78 
importImage(const QString & path)79 void Learner::importImage(const QString &path)
80 {
81     if (!QFileInfo::exists(path)) {
82         qCWarning(LIBLEARNER_LOG) << "image path points to a non-existing file, aborting: " << path;
83         return;
84     }
85 
86     // create image directory if it does not exist
87     QDir dir;
88     if (!dir.exists(d->imageDirectory())) {
89         dir.mkdir(d->imageDirectory());
90     }
91 
92     QPixmap image = QPixmap(path);
93     image = image.scaled(120, 120);
94     if (!image.save(d->imagePath(), "PNG")) {
95         qCCritical(LIBLEARNER_LOG()) << "could not save scaled image to" << d->imagePath();
96     }
97     emit imageChanged();
98     qCDebug(LIBLEARNER_LOG) << "saved scaled image from " << path << " at " << d->imagePath();
99 }
100 
goals() const101 QList<LearningGoal *> Learner::goals() const
102 {
103     return d->m_goals;
104 }
105 
addGoal(LearnerProfile::LearningGoal * goal)106 void Learner::addGoal(LearnerProfile::LearningGoal *goal)
107 {
108     if (d->m_goals.contains(goal)) {
109         return;
110     }
111     emit goalAboutToBeAdded(goal, d->m_goals.count());
112     d->m_goals.append(goal);
113     emit goalAdded();
114 }
115 
removeGoal(LearnerProfile::LearningGoal * goal)116 void Learner::removeGoal(LearnerProfile::LearningGoal *goal)
117 {
118     int index = d->m_goals.indexOf(goal);
119     if (index < 0) {
120         qCritical() << "Cannot remove goal, not found: aborting";
121         return;
122     }
123     emit goalAboutToBeRemoved(index);
124     d->m_goals.removeAt(index);
125     emit goalRemoved(this, goal);
126 }
127 
hasGoal(LearningGoal * goal) const128 bool Learner::hasGoal(LearningGoal *goal) const
129 {
130     foreach (LearningGoal *cmpGoal, d->m_goals) {
131         if (goal->identifier() == cmpGoal->identifier()) {
132             return true;
133         }
134     }
135     return false;
136 }
137 
setActiveGoal(LearningGoal * goal)138 void Learner::setActiveGoal(LearningGoal *goal)
139 {
140     if (d->m_activeGoal.contains(goal->category()) && d->m_activeGoal[goal->category()] == goal) {
141         return;
142     }
143 
144     d->m_activeGoal.insert(goal->category(), goal);
145     emit activeGoalChanged();
146 }
147 
setActiveGoal(Learner::Category categoryLearner,const QString & identifier)148 void Learner::setActiveGoal(Learner::Category categoryLearner, const QString &identifier)
149 {
150     // TODO:Qt5 change method parameter to LearningGoal::Category
151     // workaround for Q_INVOKABLE access of enum
152     LearningGoal::Category category = static_cast<LearningGoal::Category>(categoryLearner);
153 
154     if (d->m_activeGoal.contains(category) && d->m_activeGoal[category]->identifier() == identifier) {
155         return;
156     }
157 
158     foreach (LearningGoal *goal, d->m_goals) {
159         if (goal->category() == category && goal->identifier() == identifier) {
160             setActiveGoal(goal);
161             return;
162         }
163     }
164     qCritical() << "Could not select learning goal with ID " << identifier << ": not registered for this learner";
165 }
166 
activeGoal(Learner::Category categoryLearner) const167 LearningGoal *Learner::activeGoal(Learner::Category categoryLearner) const
168 {
169     // TODO:Qt5 change method parameter to LearningGoal::Category
170     // workaround for Q_INVOKABLE access of enum
171     LearningGoal::Category category = static_cast<LearningGoal::Category>(categoryLearner);
172     if (!d->m_activeGoal.contains(category)) {
173         qCWarning(LIBLEARNER_LOG) << "(Learner " << identifier() << ") No current learning goal set for category " << category << " : fall back to first in list";
174         foreach (LearningGoal *goal, d->m_goals) {
175             if (goal->category() == category) {
176                 return goal;
177             }
178         }
179         qCWarning(LIBLEARNER_LOG) << "No learning goals of category " << category << " registered";
180         return nullptr;
181     }
182     return d->m_activeGoal[category];
183 }
184