diff --git a/src/application.cpp b/src/application.cpp index 083bfa9..75cc43b 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,119 +1,121 @@ /* * Copyright 2013-2015 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "application.h" #include "core/course.h" #include "core/drawertrainingactions.h" +#include "core/trainingaction.h" #include "core/editorsession.h" #include "core/language.h" #include "core/phoneme.h" #include "core/phonemegroup.h" #include "core/phrase.h" #include "core/player.h" #include "core/recorder.h" #include "core/resourcemanager.h" #include "core/skeleton.h" #include "core/trainingsession.h" #include "core/unit.h" #include "models/coursefiltermodel.h" #include "models/coursemodel.h" #include "models/languagemodel.h" #include "models/languageresourcemodel.h" #include "models/learningprogressmodel.h" #include "models/phonemegroupmodel.h" #include "models/phonememodel.h" #include "models/phonemeunitmodel.h" #include "models/phrasefiltermodel.h" #include "models/phraselistmodel.h" #include "models/phrasemodel.h" #include "models/profilemodel.h" #include "models/skeletonmodel.h" #include "models/unitfiltermodel.h" #include "models/unitmodel.h" #include "qmlcontrols/iconitem.h" #include "liblearnerprofile/src/learner.h" #include "liblearnerprofile/src/profilemanager.h" #include "liblearnerprofile/src/learninggoal.h" #include "liblearnerprofile/src/models/learninggoalmodel.h" #include #include #include #include Application::Application(int& argc, char** argv) : QApplication(argc, argv) { registerQmlTypes(); } void Application::registerQmlTypes() { qmlRegisterUncreatableType( "artikulate", 1, 0, "TrainingSession", QStringLiteral("TrainingSession is unique object provided by the backend")); qmlRegisterUncreatableType( "artikulate", 1, 0, "EditorSession", QStringLiteral("EditorSession is unique object provided by the backend")); qmlRegisterUncreatableType( "artikulate", 1, 0, "ResourceManager", QStringLiteral("ResourceManager is unique object provided by the backend")); qmlRegisterUncreatableType( "artikulate", 1, 0, "ProfileManager", QStringLiteral("ProfileManager is unique object provided by the backend")); qmlRegisterType("artikulate", 1, 0, "Learner"); qmlRegisterType("artikulate", 1, 0, "LearningGoal"); qmlRegisterType("artikulate", 1, 0, "Unit"); qmlRegisterType("artikulate", 1, 0, "Skeleton"); qmlRegisterType("artikulate", 1, 0, "Course"); qmlRegisterType("artikulate", 1, 0, "Language"); qmlRegisterType("artikulate", 1, 0, "ResourceManager"); qmlRegisterType("artikulate", 1, 0, "Phrase"); qmlRegisterType("artikulate", 1, 0, "Phoneme"); qmlRegisterType("artikulate", 1, 0, "PhonemeGroup"); qmlRegisterType("artikulate", 1, 0, "Player"); qmlRegisterType("artikulate", 1, 0, "Recorder"); qmlRegisterType("artikulate", 1, 0, "Icon"); qmlRegisterType("artikulate", 1, 0, "DrawerTrainingActions"); + qmlRegisterType("artikulate", 1, 0, "TrainingAction"); qmlRegisterType("artikulate", 1, 0, "CourseModel"); qmlRegisterType("artikulate", 1, 0, "CourseFilterModel"); qmlRegisterType("artikulate", 1, 0, "LanguageModel"); qmlRegisterType("artikulate", 1, 0, "LanguageResourceModel"); // qmlRegisterType("artikulate", 1, 0, "LearningProgressModel");//TODO must be ported to new trainingsession qmlRegisterType("artikulate", 1, 0, "UnitModel"); qmlRegisterType("artikulate", 1, 0, "UnitFilterModel"); qmlRegisterType("artikulate", 1, 0, "PhraseModel"); qmlRegisterType("artikulate", 1, 0, "PhraseListModel"); qmlRegisterType("artikulate", 1, 0, "PhraseFilterModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeGroupModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeUnitModel"); qmlRegisterType("artikulate", 1, 0, "ProfileModel"); qmlRegisterType("artikulate", 1, 0, "SkeletonModel"); qmlRegisterType("artikulate", 1, 0, "LearningGoalModel"); } diff --git a/src/core/drawertrainingactions.cpp b/src/core/drawertrainingactions.cpp index b358735..5147c44 100644 --- a/src/core/drawertrainingactions.cpp +++ b/src/core/drawertrainingactions.cpp @@ -1,92 +1,66 @@ /* - * Copyright 2018 Andreas Cord-Landwehr + * Copyright 2018-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "drawertrainingactions.h" #include "trainingaction.h" #include "course.h" -#include "unit.h" #include #include DrawerTrainingActions::DrawerTrainingActions(QObject* parent) : QObject(parent) { } void DrawerTrainingActions::setSession(TrainingSession *session) { if (session == m_session) { return; } if (m_session) { - disconnect(m_session, &TrainingSession::courseChanged, this, &DrawerTrainingActions::updateActions); + disconnect(m_session, &TrainingSession::courseChanged, this, &DrawerTrainingActions::actionsChanged); + disconnect(m_session, &TrainingSession::phraseChanged, this, &DrawerTrainingActions::triggerTrainingView); } m_session = session; - connect(m_session, &TrainingSession::courseChanged, this, &DrawerTrainingActions::updateActions); + connect(m_session, &TrainingSession::courseChanged, this, &DrawerTrainingActions::actionsChanged); + connect(m_session, &TrainingSession::phraseChanged, this, &DrawerTrainingActions::triggerTrainingView); emit sessionChanged(); - updateActions(); + emit actionsChanged(); } TrainingSession * DrawerTrainingActions::session() const { return m_session; } -QList DrawerTrainingActions::actions() const -{ - return m_actions; -} - -void DrawerTrainingActions::updateActions() +QList DrawerTrainingActions::actions() const { if (!m_session) { - return; + return QList(); } - - // cleanup - for (const auto &action : m_actions) { - action->deleteLater(); + QList actions; + for (const auto &action : m_session->trainingActions()) { + actions.append(qobject_cast(action)); } - m_actions.clear(); - - if (!m_session->course()) { - return; - } - - for (const auto &unit : m_session->course()->unitList()) { - auto action = new TrainingAction(unit->title()); - for (const auto &phrase : unit->phraseList()) { - if (phrase->sound().isEmpty()) { - continue; - } - action->appendChild(new TrainingAction(phrase, this, unit)); - } - if (action->hasChildren()) { - m_actions.append(action); - } else { - action->deleteLater(); - } - } - - emit actionsChanged(); + return actions; } diff --git a/src/core/drawertrainingactions.h b/src/core/drawertrainingactions.h index 2f371c9..b4c86c6 100644 --- a/src/core/drawertrainingactions.h +++ b/src/core/drawertrainingactions.h @@ -1,58 +1,54 @@ /* - * Copyright 2018 Andreas Cord-Landwehr + * Copyright 2018-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DRAWERTRAININGACTIONS_H #define DRAWERTRAININGACTIONS_H #include "artikulatecore_export.h" #include "trainingaction.h" #include class Course; class ARTIKULATECORE_EXPORT DrawerTrainingActions : public QObject { Q_OBJECT Q_PROPERTY(TrainingSession *session READ session WRITE setSession NOTIFY sessionChanged) - Q_PROPERTY(QList actions READ actions NOTIFY actionsChanged) + Q_PROPERTY(QList actions READ actions NOTIFY actionsChanged) public: DrawerTrainingActions(QObject *parent = nullptr); void setSession(TrainingSession *session); TrainingSession * session() const; - QList actions() const; - -private Q_SLOTS: - void updateActions(); + QList actions() const; Q_SIGNALS: void actionsChanged(); void sessionChanged(); /** * Notify that training view shall be displayed. */ void triggerTrainingView(); private: TrainingSession *m_session{nullptr}; - QList m_actions; }; #endif diff --git a/src/core/trainingaction.cpp b/src/core/trainingaction.cpp index baf05bb..79d3c0a 100644 --- a/src/core/trainingaction.cpp +++ b/src/core/trainingaction.cpp @@ -1,87 +1,86 @@ /* - * Copyright 2018 Andreas Cord-Landwehr + * Copyright 2018-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "trainingaction.h" #include "trainingactionicon.h" #include "drawertrainingactions.h" #include "trainingsession.h" TrainingAction::TrainingAction(QObject *parent) : QObject(parent) , m_text(QString()) , m_icon(new TrainingActionIcon(this, QString())) //TODO "rating-unrated" vs. "rating" { } TrainingAction::TrainingAction(const QString &text, QObject *parent) : QObject(parent) , m_text(text) , m_icon(new TrainingActionIcon(this, QString())) //TODO "rating-unrated" vs. "rating" { } -TrainingAction::TrainingAction(Phrase *phrase, DrawerTrainingActions *drawerTrainingActions, QObject* parent) +TrainingAction::TrainingAction(Phrase *phrase, TrainingSession *session, QObject* parent) : QObject(parent) , m_icon(new TrainingActionIcon(this, QString())) , m_phrase(phrase) - , m_drawerTrainingActions(drawerTrainingActions) + , m_trainingSession(session) { if (m_phrase) { m_text = phrase->text(); } } void TrainingAction::appendChild(QObject* child) { m_children.append(child); emit childrenChanged(); } bool TrainingAction::hasChildren() const { return m_children.count() > 0; } void TrainingAction::trigger() { - if (m_phrase && m_drawerTrainingActions && m_drawerTrainingActions->session()) { - m_drawerTrainingActions->session()->setPhrase(m_phrase); - emit m_drawerTrainingActions->triggerTrainingView(); + if (m_phrase && m_trainingSession) { + m_trainingSession->setPhrase(m_phrase); } } bool TrainingAction::enabled() const { return m_enabled; } void TrainingAction::setEnabled(bool enabled) { if (enabled == m_enabled) { return; } m_enabled = enabled; emit enabledChanged(m_enabled); } QObject * TrainingAction::icon() const { return m_icon; } diff --git a/src/core/trainingaction.h b/src/core/trainingaction.h index 95aaaef..deb8ca5 100644 --- a/src/core/trainingaction.h +++ b/src/core/trainingaction.h @@ -1,74 +1,74 @@ /* - * Copyright 2018 Andreas Cord-Landwehr + * Copyright 2018-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TRAININGACTION_H #define TRAININGACTION_H #include "artikulatecore_export.h" #include "trainingactionicon.h" #include "phrase.h" #include "trainingsession.h" #include #include class DrawerTrainingActions; class ARTIKULATECORE_EXPORT TrainingAction : public QObject { Q_OBJECT Q_PROPERTY(QString text MEMBER m_text CONSTANT) Q_PROPERTY(QObject* icon READ icon CONSTANT) Q_PROPERTY(bool visible MEMBER m_visible CONSTANT) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool checked MEMBER m_checked CONSTANT) Q_PROPERTY(QString tooltip MEMBER m_tooltip CONSTANT) Q_PROPERTY(QList children MEMBER m_children NOTIFY childrenChanged) Q_PROPERTY(bool checkable MEMBER m_checkable CONSTANT) Q_SIGNALS: void changed(); void childrenChanged(); void enabledChanged(bool enabled); public: TrainingAction(QObject *parent = nullptr); TrainingAction(const QString &text, QObject *parent = nullptr); - TrainingAction(Phrase *phrase, DrawerTrainingActions *drawerActions, QObject *parent = nullptr); + TrainingAction(Phrase *phrase, TrainingSession *session, QObject *parent = nullptr); void appendChild(QObject *child); bool hasChildren() const; Q_INVOKABLE void trigger(); bool enabled() const; void setEnabled(bool enabled); QObject * icon() const; private: QString m_text; TrainingActionIcon *m_icon{nullptr}; bool m_visible{true}; bool m_enabled{true}; bool m_checked{false}; bool m_checkable{false}; QString m_tooltip{QString()}; QList m_children; Phrase *m_phrase{nullptr}; - DrawerTrainingActions * m_drawerTrainingActions{nullptr}; + TrainingSession * m_trainingSession{nullptr}; }; #endif diff --git a/src/core/trainingsession.cpp b/src/core/trainingsession.cpp index c8b141b..6ba9b8b 100644 --- a/src/core/trainingsession.cpp +++ b/src/core/trainingsession.cpp @@ -1,203 +1,232 @@ /* - * Copyright 2013-2016 Andreas Cord-Landwehr + * Copyright 2013-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "trainingsession.h" #include "core/language.h" #include "core/course.h" #include "core/unit.h" #include "core/phrase.h" -#include "core/phonemegroup.h" #include "profilemanager.h" #include "learner.h" +#include "trainingaction.h" #include "artikulate_debug.h" TrainingSession::TrainingSession(QObject *parent) : QObject(parent) , m_profileManager(nullptr) , m_course(nullptr) , m_unit(nullptr) , m_phrase(nullptr) { } void TrainingSession::setProfileManager(LearnerProfile::ProfileManager *manager) { if (m_profileManager == manager) { return; } m_profileManager = manager; } Course * TrainingSession::course() const { return m_course; } void TrainingSession::setCourse(Course *course) { if (!course) { return; } if (m_course == course) { return; } m_course = course; if (m_course && m_course->unitList().count() > 0) { setUnit(m_course->unitList().first()); } // lazy loading of training data LearnerProfile::LearningGoal * goal = m_profileManager->goal( LearnerProfile::LearningGoal::Language, m_course->id()); if (!goal) { goal = m_profileManager->registerGoal( LearnerProfile::LearningGoal::Language, course->language()->id(), course->language()->i18nTitle() ); } auto data = m_profileManager->progressValues(m_profileManager->activeProfile(), goal, m_course->id() ); Q_FOREACH(Unit *unit, m_course->unitList()) { Q_FOREACH(Phrase *phrase, unit->phraseList()) { auto iter = data.find(phrase->id()); if (iter != data.end()) { phrase->setProgress(iter.value()); } } } emit courseChanged(); } Unit * TrainingSession::unit() const { return m_unit; } void TrainingSession::setUnit(Unit *unit) { if (m_unit == unit) { return; } m_unit = unit; if (m_unit && m_unit->phraseList().count() > 0) { setPhrase(m_unit->phraseList().first()); } return unitChanged(); } Phrase * TrainingSession::phrase() const { return m_phrase; } void TrainingSession::setPhrase(Phrase *phrase) { if (m_phrase == phrase) { return; } setUnit(phrase->unit()); m_phrase = phrase; return phraseChanged(); } Phrase * TrainingSession::nextPhrase() const { if (!m_phrase) { return nullptr; } const int index = m_phrase->unit()->phraseList().indexOf(m_phrase); if (index < m_phrase->unit()->phraseList().length() - 1) { return m_phrase->unit()->phraseList().at(index + 1); } else { Unit *unit = m_phrase->unit(); int uIndex = unit->course()->unitList().indexOf(unit); if (uIndex < unit->course()->unitList().length() - 1) { return unit->course()->unitList().at(uIndex + 1)->phraseList().first(); } } return nullptr; } void TrainingSession::showNextPhrase() { // possibly update goals of learner updateGoal(); m_phrase->updateProgress(Phrase::Progress::Done); // store training activity LearnerProfile::LearningGoal * goal = m_profileManager->goal( LearnerProfile::LearningGoal::Language, m_course->language()->id()); m_profileManager->recordProgress(m_profileManager->activeProfile(), goal, m_course->id(), m_phrase->id(), static_cast(LearnerProfile::ProfileManager::Skip), m_phrase->progress() ); setPhrase(nextPhrase()); } void TrainingSession::skipPhrase() { // possibly update goals of learner updateGoal(); m_phrase->updateProgress(Phrase::Progress::Skip); // store training activity LearnerProfile::LearningGoal * goal = m_profileManager->goal( LearnerProfile::LearningGoal::Language, m_course->language()->id()); m_profileManager->recordProgress(m_profileManager->activeProfile(), goal, m_course->id(), m_phrase->id(), static_cast(LearnerProfile::ProfileManager::Skip), m_phrase->progress() ); setPhrase(nextPhrase()); } bool TrainingSession::hasNextPhrase() const { return nextPhrase() != nullptr; } void TrainingSession::updateGoal() { if (!m_profileManager) { qCWarning(ARTIKULATE_LOG) << "No ProfileManager registered, aborting operation"; return; } LearnerProfile::Learner *learner = m_profileManager->activeProfile(); if (!learner) { qCWarning(ARTIKULATE_LOG) << "No active Learner registered, aborting operation"; return; } LearnerProfile::LearningGoal * goal = m_profileManager->goal( LearnerProfile::LearningGoal::Language, m_course->language()->id()); learner->addGoal(goal); learner->setActiveGoal(goal); } + +QVector TrainingSession::trainingActions() +{ + // cleanup + for (const auto &action : m_actions) { + action->deleteLater(); + } + m_actions.clear(); + + if (!m_course) { + return QVector(); + } + + for (const auto &unit : m_course->unitList()) { + auto action = new TrainingAction(unit->title()); + for (const auto &phrase : unit->phraseList()) { + if (phrase->sound().isEmpty()) { + continue; + } + action->appendChild(new TrainingAction(phrase, this, unit)); + } + if (action->hasChildren()) { + m_actions.append(action); + } else { + action->deleteLater(); + } + } + return m_actions; +} diff --git a/src/core/trainingsession.h b/src/core/trainingsession.h index 8b16957..33f3682 100644 --- a/src/core/trainingsession.h +++ b/src/core/trainingsession.h @@ -1,81 +1,84 @@ /* * Copyright 2013-2015 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TRAININGSESSION_H #define TRAININGSESSION_H #include "artikulatecore_export.h" #include "course.h" #include "phrase.h" +#include class QString; class Language; class Course; class Unit; -class PhonemeGroup; +class TrainingAction; namespace LearnerProfile { class ProfileManager; } /** * \class TrainingSession */ class ARTIKULATECORE_EXPORT TrainingSession : public QObject { Q_OBJECT Q_PROPERTY(Course *course READ course WRITE setCourse NOTIFY courseChanged) Q_PROPERTY(Unit *unit READ unit WRITE setUnit NOTIFY unitChanged) Q_PROPERTY(Phrase *phrase READ phrase WRITE setPhrase NOTIFY phraseChanged) Q_PROPERTY(bool hasNextPhrase READ hasNextPhrase NOTIFY phraseChanged) public: explicit TrainingSession(QObject *parent = nullptr); void setProfileManager(LearnerProfile::ProfileManager *manager); Course * course() const; void setCourse(Course *course); Unit * unit() const; void setUnit(Unit *unit); Phrase::Type phraseType() const; void setPhraseType(Phrase::Type type); Phrase * phrase() const; void setPhrase(Phrase *phrase); bool hasPreviousPhrase() const; bool hasNextPhrase() const; Q_INVOKABLE void showNextPhrase(); Q_INVOKABLE void skipPhrase(); + QVector trainingActions(); Q_SIGNALS: void courseChanged(); void unitChanged(); void phraseChanged(); private: Q_DISABLE_COPY(TrainingSession) Phrase * nextPhrase() const; void updateGoal(); LearnerProfile::ProfileManager *m_profileManager; Course *m_course; Unit *m_unit; Phrase *m_phrase; + QVector m_actions; }; #endif