diff --git a/autotests/integrationtests/iresourcerepository_integration/test_iresourcerepository.cpp b/autotests/integrationtests/iresourcerepository_integration/test_iresourcerepository.cpp index 42a5cab..ec9752b 100644 --- a/autotests/integrationtests/iresourcerepository_integration/test_iresourcerepository.cpp +++ b/autotests/integrationtests/iresourcerepository_integration/test_iresourcerepository.cpp @@ -1,97 +1,97 @@ /* * Copyright 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 "test_iresourcerepository.h" -#include -#include #include +#include +#include -#include "core/resourcerepository.h" +#include "../src/settings.h" #include "core/contributorrepository.h" -#include "core/language.h" #include "core/icourse.h" +#include "core/language.h" +#include "core/resourcerepository.h" #include "core/unit.h" -#include "../src/settings.h" TestIResourceRepository::TestIResourceRepository() : m_repositoryLocation(QUrl::fromLocalFile(qApp->applicationDirPath() + "/../autotests/integrationtests/data/")) { qDebug() << "Running test with repository root:" << m_repositoryLocation; } void TestIResourceRepository::init() { // check that test data is deployed at the expected location QVERIFY(QFile::exists(m_repositoryLocation.toLocalFile() + "/courses/de/de.xml")); QVERIFY(QFile::exists(m_repositoryLocation.toLocalFile() + "/courses/fr/fr.xml")); } void TestIResourceRepository::resourceRepository() { ResourceRepository repository(QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/courses/")); QCOMPARE(repository.storageLocation(), QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/courses/")); performInterfaceTests(&repository); } void TestIResourceRepository::contributorRepository() { ContributorRepository repository(QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/contributorrepository/")); // contributor repository requires subdirectory "courses" QCOMPARE(repository.storageLocation(), QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/contributorrepository/")); performInterfaceTests(&repository); } void TestIResourceRepository::performInterfaceTests(IResourceRepository *interface) { QVERIFY(interface->languages().count() > 0); // automatically load languages - QCOMPARE(interface->courses().count(), 0); // load courses only on demand + QCOMPARE(interface->courses().count(), 0); // load courses only on demand // test adding QSignalSpy spyAboutToBeAdded(dynamic_cast(interface), SIGNAL(courseAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(dynamic_cast(interface), SIGNAL(courseAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); interface->reloadCourses(); // initial loading of courses QCOMPARE(interface->courses().count(), 2); QCOMPARE(spyAboutToBeAdded.count(), 2); QCOMPARE(spyAdded.count(), 2); // test reloading of courses interface->reloadCourses(); // initial loading of courses QCOMPARE(interface->courses().count(), 2); // test removal // note: repository does not provide removal of courses, yet // test access of courses grouped by language auto languages = interface->languages(); std::shared_ptr german; for (auto language : interface->languages()) { if (language->id() == "de") { german = language; break; } } - QVERIFY(german != nullptr); // ensure that German language was found + QVERIFY(german != nullptr); // ensure that German language was found QCOMPARE(interface->courses(german->id()).count(), 1); // there is exactly one German course - QCOMPARE(interface->courses(nullptr).count(), 2); // all courses in total are 2 + QCOMPARE(interface->courses(nullptr).count(), 2); // all courses in total are 2 QVERIFY(interface->courses().first()->units().size() > 0); } QTEST_GUILESS_MAIN(TestIResourceRepository) diff --git a/autotests/mocks/coursestub.h b/autotests/mocks/coursestub.h index d1822e9..7b8d9b5 100644 --- a/autotests/mocks/coursestub.h +++ b/autotests/mocks/coursestub.h @@ -1,105 +1,104 @@ /* * Copyright 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 COURSESTUB_H #define COURSESTUB_H #include "src/core/icourse.h" #include "src/core/language.h" #include "src/core/unit.h" #include class CourseStub : public ICourse { public: CourseStub(std::shared_ptr language, QVector> units) : m_language(language) , m_units(units) { } ~CourseStub() override; static std::shared_ptr create(std::shared_ptr language, QVector> units) { auto course = std::make_shared(language, units); course->setSelf(course); return std::static_pointer_cast(course); } void setSelf(std::shared_ptr self) override { m_self = self; } QString id() const override { return "courseid"; } QString foreignId() const override { return "foreigncourseid"; } QString title() const override { return m_title; } void setTitle(QString title) { m_title = title; emit titleChanged(); } QString i18nTitle() const override { return "i18n title"; } QString description() const override { return "description of the course"; } std::shared_ptr language() const override { return m_language; } QString languageTitle() const override { if (m_language) { m_language->title(); } return QString(); } QVector> units() override { return m_units; } QUrl file() const override { return QUrl(); } private: - QString m_title{ "title" }; + QString m_title {"title"}; std::weak_ptr m_self; std::shared_ptr m_language; QVector> m_units; }; - #endif diff --git a/autotests/mocks/editablecoursestub.h b/autotests/mocks/editablecoursestub.h index 3fa6c66..809f913 100644 --- a/autotests/mocks/editablecoursestub.h +++ b/autotests/mocks/editablecoursestub.h @@ -1,162 +1,162 @@ /* * Copyright 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 EDITABLECOURSESTUB_H #define EDITABLECOURSESTUB_H #include "src/core/ieditablecourse.h" #include "src/core/ilanguage.h" #include "src/core/unit.h" #include class EditableCourseStub : public IEditableCourse { public: EditableCourseStub(std::shared_ptr language, QVector> units) : IEditableCourse() , m_language(language) , m_units(units) { } ~EditableCourseStub() override; static std::shared_ptr create(std::shared_ptr language, QVector> units) { auto course = std::make_shared(language, units); course->setSelf(course); for (auto &unit : units) { unit->setCourse(course); } return std::static_pointer_cast(course); } void setSelf(std::shared_ptr self) override { m_self = self; } std::shared_ptr self() const override { return std::static_pointer_cast(m_self.lock()); } QString id() const override { return m_id; } void setId(QString id) override { m_id = id; emit idChanged(); } QString foreignId() const override { return m_foreignId; } void setForeignId(QString id) override { m_foreignId = id; } QString title() const override { return m_title; } void setTitle(QString title) override { m_title = title; emit titleChanged(); } QString i18nTitle() const override { return m_i18nTitle; } void setI18nTitle(QString title) override { m_i18nTitle = title; } QString description() const override { return m_description; } void setDescription(QString description) override { m_description = description; emit descriptionChanged(); } std::shared_ptr language() const override { return m_language; } QString languageTitle() const override { if (m_language) { m_language->title(); } return QString(); } void setLanguage(std::shared_ptr language) override { m_language = language; emit languageChanged(); } QVector> units() override { return m_units; } std::shared_ptr addUnit(std::shared_ptr unit) override { m_units.append(std::move(unit)); auto unitPtr = m_units.last(); unitPtr->setCourse(self()); return unitPtr; } QUrl file() const override { return QUrl(); } bool sync() override { return false; } void updateFrom(std::shared_ptr) override { // not implemented } bool isModified() const override { return false; } bool exportToFile(const QUrl &) const override { // do nothing return false; } private: std::weak_ptr m_self; - QString m_id{ "courseid" }; - QString m_foreignId{ "foreigncourseid" }; - QString m_title{ "title" }; - QString m_i18nTitle{ "i18n title" }; - QString m_description{ "description of the course" }; + QString m_id {"courseid"}; + QString m_foreignId {"foreigncourseid"}; + QString m_title {"title"}; + QString m_i18nTitle {"i18n title"}; + QString m_description {"description of the course"}; std::shared_ptr m_language; QVector> m_units; }; #endif diff --git a/autotests/mocks/editablerepositorystub.h b/autotests/mocks/editablerepositorystub.h index ae28b53..f085571 100644 --- a/autotests/mocks/editablerepositorystub.h +++ b/autotests/mocks/editablerepositorystub.h @@ -1,140 +1,137 @@ /* * Copyright 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 EDITABLEREPOSITORYSTUB_H #define EDITABLEREPOSITORYSTUB_H -#include "core/ieditablerepository.h" #include "core/ieditablecourse.h" +#include "core/ieditablerepository.h" #include #include class ILanguage; class SkeletonResource; /** * @brief The EditableRepositoryStub is simple sub class only for testing */ class EditableRepositoryStub : public IEditableRepository { Q_OBJECT public: - EditableRepositoryStub( - std::vector> languages, - std::vector> skeletons, - std::vector> courses) + EditableRepositoryStub(std::vector> languages, std::vector> skeletons, std::vector> courses) { for (auto &language : languages) { m_languages.append(std::move(language)); } for (auto &skeleton : skeletons) { m_skeletons.append(std::move(skeleton)); } for (auto &course : courses) { m_courses.append(course); } } ~EditableRepositoryStub() override; QUrl storageLocation() const override { return QUrl(); } QVector> skeletons() const override { return m_skeletons; } QVector> editableCourses() const override { return m_courses; } QVector> courses() const override { QVector> courses; for (auto course : m_courses) { courses.push_back(course); } return courses; } QVector> courses(const QString &languageId) const override { Q_UNUSED(languageId); return QVector>(); } std::shared_ptr editableCourse(std::shared_ptr language, int index) const override { Q_UNUSED(language); Q_UNUSED(index); return std::shared_ptr(); } void reloadCourses() override { // do nothing } QVector> languages() const override { return m_languages; } void appendCourse(std::shared_ptr course) { emit courseAboutToBeAdded(course, m_courses.count()); m_courses.append(course); emit courseAdded(); } void removeCourse(std::shared_ptr course) { auto index = m_courses.indexOf(course); Q_ASSERT(index >= 0); if (index >= 0) { emit courseAboutToBeRemoved(index); m_courses.remove(index); emit courseRemoved(); } } void appendSkeleton(std::shared_ptr skeleton) { emit skeletonAboutToBeAdded(skeleton, m_skeletons.count()); m_skeletons.append(skeleton); emit skeletonAdded(); } void removeSkeleton(std::shared_ptr skeleton) { auto index = m_skeletons.indexOf(skeleton); Q_ASSERT(index >= 0); if (index >= 0) { emit skeletonAboutToBeRemoved(index); m_skeletons.remove(index); emit skeletonRemoved(); } } void updateCourseFromSkeleton(std::shared_ptr course) override { Q_UNUSED(course); // do nothing } private: QVector> m_languages; QVector> m_skeletons; QVector> m_courses; }; #endif diff --git a/autotests/mocks/languagestub.h b/autotests/mocks/languagestub.h index f05c241..2f03f6e 100644 --- a/autotests/mocks/languagestub.h +++ b/autotests/mocks/languagestub.h @@ -1,88 +1,86 @@ /* * Copyright 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 LANGUAGESTUB_H #define LANGUAGESTUB_H -#include "src/core/ilanguage.h" #include "core/phonemegroup.h" +#include "src/core/ilanguage.h" #include #include class Phoneme; class PhonemeGroup; class LanguageStub : public ILanguage { public: LanguageStub(QString id) : m_id(id) { } ~LanguageStub() override; QString id() const override { return m_id; } QString title() const override { return m_title; } void setTitle(QString title) { m_title = title; emit titleChanged(); } QString i18nTitle() const override { return "i18n title"; } QVector> phonemes() const override { QVector> phonemes; for (auto group : m_phonemeGroups) { phonemes.append(group->phonemes()); } return phonemes; } QVector> phonemeGroups() const override { return m_phonemeGroups; } std::shared_ptr addPhonemeGroup(const QString &identifier, const QString &title) { std::shared_ptr phonemeGroup(new PhonemeGroup); phonemeGroup->setId(identifier); phonemeGroup->setTitle(title); m_phonemeGroups.append(phonemeGroup); return phonemeGroup; } - private: - QString m_id{ "UNKNOWN_ID" }; - QString m_title{ "title" }; + QString m_id {"UNKNOWN_ID"}; + QString m_title {"title"}; QVector> m_phonemeGroups; }; - #endif diff --git a/autotests/mocks/resourcerepositorystub.h b/autotests/mocks/resourcerepositorystub.h index 866ce86..0f7e637 100644 --- a/autotests/mocks/resourcerepositorystub.h +++ b/autotests/mocks/resourcerepositorystub.h @@ -1,115 +1,115 @@ /* * Copyright 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 RESOURCEREPOSITORYSTUB_H #define RESOURCEREPOSITORYSTUB_H #include "core/iresourcerepository.h" #include "core/language.h" +#include #include #include -#include class ICourse; /** * @brief The ResourceRepositoryStub that only provides languages and a storage location, but nothing else */ class ResourceRepositoryStub : public IResourceRepository { Q_OBJECT public: ResourceRepositoryStub(std::vector> languages) { for (auto &language : languages) { m_languages.append(std::move(language)); } } ResourceRepositoryStub(std::vector> languages) { for (auto &language : languages) { m_languages.append(language); } } ResourceRepositoryStub(std::vector> languages, std::vector> courses) { for (auto &language : languages) { m_languages.append(language); } for (auto &course : courses) { m_courses.append(course); } } ~ResourceRepositoryStub() override; QUrl storageLocation() const override { return m_storageLocation; } QVector> courses() const override { return m_courses; } QVector> courses(const QString &languageId) const override { Q_UNUSED(languageId); return m_courses; // do not filter by languages } void reloadCourses() override { ; // do nothing, stub shall only provide languages } QVector> languages() const override { return m_languages; } void appendCourse(std::shared_ptr course) { emit courseAboutToBeAdded(course, m_courses.count()); m_courses.append(course); emit courseAdded(); } void removeCourse(std::shared_ptr course) { auto index = m_courses.indexOf(course); Q_ASSERT(index >= 0); if (index >= 0) { emit courseAboutToBeRemoved(index); m_courses.remove(index); emit courseRemoved(); } } private: QUrl m_storageLocation; QVector> m_languages; QVector> m_courses; }; #endif diff --git a/autotests/resourcetests/languageresources/testlanguagefiles.cpp b/autotests/resourcetests/languageresources/testlanguagefiles.cpp index 518a14c..b6bf9d8 100644 --- a/autotests/resourcetests/languageresources/testlanguagefiles.cpp +++ b/autotests/resourcetests/languageresources/testlanguagefiles.cpp @@ -1,97 +1,97 @@ /* * Copyright 2013 Oindrila Gupta * * 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 "testlanguagefiles.h" #include "core/language.h" -#include "core/unit.h" -#include "core/phrase.h" #include "core/phoneme.h" #include "core/phonemegroup.h" +#include "core/phrase.h" #include "core/resources/courseparser.h" +#include "core/unit.h" -#include -#include #include +#include +#include #include TestLanguageFiles::TestLanguageFiles() { } void TestLanguageFiles::init() { // TODO initialization of test case } void TestLanguageFiles::cleanup() { // TODO cleanup after test run } void TestLanguageFiles::loadGerman() { QUrl file = QUrl::fromLocalFile(":/artikulate/languages/de.xml"); auto language = Language::create(file); QCOMPARE(language->id(), "de"); QCOMPARE(language->title(), "Deutsch"); QCOMPARE(language->i18nTitle(), "German"); std::shared_ptr group; for (auto iter : language->phonemeGroups()) { if (iter->id() == "monophthonge") { group = iter; break; } } QVERIFY(group); QCOMPARE(group->id(), "monophthonge"); QCOMPARE(group->title(), "Vokalsystem Monophthonge"); QCOMPARE(group->description(), "Monophthonge"); std::shared_ptr phoneme; for (auto iter : language->phonemes()) { if (iter->id() == "a") { phoneme = iter; break; } } QVERIFY(phoneme); QCOMPARE(phoneme->id(), "a"); QCOMPARE(phoneme->title(), "[a] Kamm"); } void TestLanguageFiles::checkIdUniqueness() { QDirIterator iter(QDir(":/artikulate/languages/")); while (iter.hasNext()) { const QString &file = iter.next(); qDebug() << "File being parsed: " << file; QStringList idList; auto language = Language::create(QUrl::fromLocalFile(file)); for (auto phoneme : language->phonemes()) { QVERIFY2(!idList.contains(phoneme->id()), "Phoneme ID used more than once in the tested file"); idList.append(phoneme->id()); } } } QTEST_GUILESS_MAIN(TestLanguageFiles) diff --git a/autotests/resourcetests/xsdschemes/testxsdschemes.cpp b/autotests/resourcetests/xsdschemes/testxsdschemes.cpp index 0c00a01..47d8041 100644 --- a/autotests/resourcetests/xsdschemes/testxsdschemes.cpp +++ b/autotests/resourcetests/xsdschemes/testxsdschemes.cpp @@ -1,67 +1,67 @@ /* * Copyright 2013 Oindrila Gupta * * 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 "testxsdschemes.h" -#include #include +#include #include #include #include TestXsdSchemes::TestXsdSchemes() { } void TestXsdSchemes::init() { // TODO initialization of test case } void TestXsdSchemes::cleanup() { // TODO cleanup after test run } void TestXsdSchemes::languageSchemeValidationTest() { QUrl languageFile = QUrl::fromLocalFile(":/artikulate/schemes/language.xsd"); QXmlSchema languageSchema; QVERIFY(languageSchema.load(languageFile)); QVERIFY(languageSchema.isValid()); } void TestXsdSchemes::courseSchemeValidationTest() { QUrl schemeFile = QUrl::fromLocalFile(":/artikulate/schemes/course.xsd"); QXmlSchema courseSchema; QVERIFY(courseSchema.load(schemeFile)); QVERIFY(courseSchema.isValid()); } void TestXsdSchemes::schemeValidationTest() { QUrl skeletonFile = QUrl::fromLocalFile(":/artikulate/schemes/skeleton.xsd"); QXmlSchema skeletonScheme; QVERIFY(skeletonScheme.load(skeletonFile)); QVERIFY(skeletonScheme.isValid()); } QTEST_GUILESS_MAIN(TestXsdSchemes) diff --git a/autotests/unittests/coursemodel/test_coursemodel.cpp b/autotests/unittests/coursemodel/test_coursemodel.cpp index b9756d6..1c1c58d 100644 --- a/autotests/unittests/coursemodel/test_coursemodel.cpp +++ b/autotests/unittests/coursemodel/test_coursemodel.cpp @@ -1,128 +1,128 @@ /* * Copyright 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 "test_coursemodel.h" +#include "../mocks/coursestub.h" +#include "../mocks/languagestub.h" +#include "../mocks/resourcerepositorystub.h" #include "src/core/icourse.h" #include "src/core/language.h" #include "src/models/coursemodel.h" -#include "../mocks/resourcerepositorystub.h" -#include "../mocks/coursestub.h" -#include "../mocks/languagestub.h" -#include #include +#include void TestCourseModel::init() { // TODO initialization of test case } void TestCourseModel::cleanup() { // TODO cleanup after test run } void TestCourseModel::testInit() { // boilerplate std::shared_ptr language(new LanguageStub("de")); std::vector> languages; languages.push_back(language); auto course = CourseStub::create(language, QVector>({})); ResourceRepositoryStub repository(languages, {course}); // test initialization CourseModel model(&repository); QVERIFY(model.resourceRepository() == &repository); QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.course(0).value(), course.get()); + QCOMPARE(model.course(0).value(), course.get()); } void TestCourseModel::testAddRemoveOperations() { // boilerplate std::shared_ptr language(new LanguageStub("de")); std::vector> languages; languages.push_back(language); ResourceRepositoryStub repository(languages, {}); // test initialization CourseModel model(&repository); QVERIFY(model.resourceRepository() == &repository); QCOMPARE(model.rowCount(), 0); auto course = CourseStub::create(language, QVector>({})); { // add course - QSignalSpy spyAboutToBeAdded(&repository, SIGNAL(courseAboutToBeAdded(std::shared_ptr,int))); + QSignalSpy spyAboutToBeAdded(&repository, SIGNAL(courseAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(&repository, SIGNAL(courseAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); repository.appendCourse(course); QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.course(0).value(), course.get()); + QCOMPARE(model.course(0).value(), course.get()); QCOMPARE(spyAboutToBeAdded.count(), 1); QCOMPARE(spyAdded.count(), 1); } { // remove course QSignalSpy spyAboutToBeRemoved(&repository, SIGNAL(courseAboutToBeRemoved(int))); QSignalSpy spyRemoved(&repository, SIGNAL(courseRemoved())); QCOMPARE(spyAboutToBeRemoved.count(), 0); QCOMPARE(spyRemoved.count(), 0); repository.removeCourse(course); QCOMPARE(model.rowCount(), 0); QCOMPARE(spyAboutToBeRemoved.count(), 1); QCOMPARE(spyRemoved.count(), 1); } } void TestCourseModel::testDataChangedSignals() { // boilerplate std::shared_ptr language(new LanguageStub("de")); std::vector> languages; languages.push_back(language); auto course = CourseStub::create(language, QVector>({})); ResourceRepositoryStub repository(languages, {course}); // test initialization CourseModel model(&repository); QVERIFY(model.resourceRepository() == &repository); QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.course(0).value(), course.get()); + QCOMPARE(model.course(0).value(), course.get()); { // test adding of connections - QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &,const QModelIndex &, const QVector))); + QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector))); QCOMPARE(spyUpdate.count(), 0); std::static_pointer_cast(course)->setTitle("TitleSwitched"); QCOMPARE(spyUpdate.count(), 1); } { // test removal of connections - QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &,const QModelIndex &, const QVector))); + QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector))); QCOMPARE(spyUpdate.count(), 0); repository.removeCourse(course); std::static_pointer_cast(course)->setTitle("TitleSwitchedAgain"); QCOMPARE(spyUpdate.count(), 0); } } QTEST_GUILESS_MAIN(TestCourseModel) diff --git a/autotests/unittests/courseresource/test_courseresource.cpp b/autotests/unittests/courseresource/test_courseresource.cpp index f4413ad..7e47504 100644 --- a/autotests/unittests/courseresource/test_courseresource.cpp +++ b/autotests/unittests/courseresource/test_courseresource.cpp @@ -1,192 +1,192 @@ /* * Copyright 2013 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 "test_courseresource.h" -#include "resourcerepositorystub.h" +#include "../mocks/languagestub.h" #include "core/language.h" -#include "core/unit.h" -#include "core/phrase.h" #include "core/phonemegroup.h" +#include "core/phrase.h" #include "core/resources/courseresource.h" -#include "../mocks/languagestub.h" -#include +#include "core/unit.h" +#include "resourcerepositorystub.h" #include -#include -#include -#include +#include #include +#include +#include +#include +#include #include #include -#include TestCourseResource::TestCourseResource() { } void TestCourseResource::init() { } void TestCourseResource::cleanup() { } void TestCourseResource::loadCourseResource() { std::shared_ptr language(new LanguageStub("de")); auto group = std::static_pointer_cast(language)->addPhonemeGroup("id", "title"); group->addPhoneme("g", "G"); group->addPhoneme("u", "U"); std::vector> languages; languages.push_back(language); ResourceRepositoryStub repository(languages); const QString courseDirectory = qApp->applicationDirPath() + "/../autotests/unittests/data/courses/de/"; const QString courseFile = courseDirectory + "de.xml"; auto course = CourseResource::create(QUrl::fromLocalFile(courseFile), &repository); QCOMPARE(course->file().toLocalFile(), courseFile); QCOMPARE(course->id(), "de"); QCOMPARE(course->foreignId(), "artikulate-basic"); QCOMPARE(course->title(), "Artikulate Deutsch"); QCOMPARE(course->description(), "Ein Kurs in (hoch-)deutscher Aussprache."); QVERIFY(course->language() != nullptr); QCOMPARE(course->language()->id(), "de"); QCOMPARE(course->units().count(), 1); QCOMPARE(course->units().first()->course(), course); const auto unit = course->units().first(); QVERIFY(unit != nullptr); QCOMPARE(unit->id(), "1"); QCOMPARE(unit->title(), QStringLiteral("Auf der Straße")); QCOMPARE(unit->foreignId(), "{dd60f04a-eb37-44b7-9787-67aaf7d3578d}"); QCOMPARE(unit->course(), course); QCOMPARE(unit->phrases().count(), 3); // note: this test takes the silent assumption that phrases are added to the list in same // order as they are defined in the file. This assumption should be made explicit or dropped const auto firstPhrase = unit->phrases().first(); QVERIFY(firstPhrase != nullptr); QCOMPARE(firstPhrase->id(), "1"); QCOMPARE(firstPhrase->foreignId(), "{3a4c1926-60d7-44c6-80d1-03165a641c75}"); QCOMPARE(firstPhrase->text(), "Guten Tag."); QCOMPARE(firstPhrase->soundFileUrl(), courseDirectory + "de_01.ogg"); QCOMPARE(firstPhrase->type(), Phrase::Type::Sentence); QCOMPARE(firstPhrase->phonemes().count(), 2); } void TestCourseResource::unitAddAndRemoveHandling() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); const QString courseDirectory = qApp->applicationDirPath() + "/../autotests/unittests/data/courses/de/"; const QString courseFile = courseDirectory + "de.xml"; auto course = CourseResource::create(QUrl::fromLocalFile(courseFile), &repository); // begin of test auto unit = Unit::create(); unit->setId("testunit"); const int initialUnitNumber = course->units().count(); QCOMPARE(initialUnitNumber, 1); QSignalSpy spyAboutToBeAdded(course.get(), SIGNAL(unitAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(course.get(), SIGNAL(unitAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); auto sharedUnit = course->addUnit(std::move(unit)); QCOMPARE(course->units().count(), initialUnitNumber + 1); QCOMPARE(spyAboutToBeAdded.count(), 1); QCOMPARE(spyAdded.count(), 1); QCOMPARE(sharedUnit->course(), course); } void TestCourseResource::coursePropertyChanges() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); const QString courseDirectory = qApp->applicationDirPath() + "/../autotests/unittests/data/courses/de/"; const QString courseFile = courseDirectory + "de.xml"; auto course = CourseResource::create(QUrl::fromLocalFile(courseFile), &repository); // id { const QString value = "newId"; QSignalSpy spy(course.get(), SIGNAL(idChanged())); QCOMPARE(spy.count(), 0); course->setId(value); QCOMPARE(course->id(), value); QCOMPARE(spy.count(), 1); } // foreign id { const QString value = "newForeignId"; QSignalSpy spy(course.get(), SIGNAL(foreignIdChanged())); QCOMPARE(spy.count(), 0); course->setForeignId(value); QCOMPARE(course->foreignId(), value); QCOMPARE(spy.count(), 1); } // title { const QString value = "newTitle"; QSignalSpy spy(course.get(), SIGNAL(titleChanged())); QCOMPARE(spy.count(), 0); course->setTitle(value); QCOMPARE(course->title(), value); QCOMPARE(spy.count(), 1); } // title { const QString value = "newI18nTitle"; QSignalSpy spy(course.get(), SIGNAL(i18nTitleChanged())); QCOMPARE(spy.count(), 0); course->setI18nTitle(value); QCOMPARE(course->i18nTitle(), value); QCOMPARE(spy.count(), 1); } // description { const QString value = "newDescription"; QSignalSpy spy(course.get(), SIGNAL(descriptionChanged())); QCOMPARE(spy.count(), 0); course->setDescription(value); QCOMPARE(course->description(), value); QCOMPARE(spy.count(), 1); } // language { std::shared_ptr testLanguage; QSignalSpy spy(course.get(), SIGNAL(languageChanged())); QCOMPARE(spy.count(), 0); course->setLanguage(testLanguage); QCOMPARE(course->language(), testLanguage); QCOMPARE(spy.count(), 1); } } QTEST_GUILESS_MAIN(TestCourseResource) diff --git a/autotests/unittests/editablecourseresource/test_editablecourseresource.cpp b/autotests/unittests/editablecourseresource/test_editablecourseresource.cpp index 9fea457..a2a9f25 100644 --- a/autotests/unittests/editablecourseresource/test_editablecourseresource.cpp +++ b/autotests/unittests/editablecourseresource/test_editablecourseresource.cpp @@ -1,363 +1,363 @@ /* * 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 "test_editablecourseresource.h" -#include "resourcerepositorystub.h" +#include "../mocks/coursestub.h" +#include "../mocks/languagestub.h" #include "core/language.h" -#include "core/unit.h" #include "core/phrase.h" #include "core/resources/courseparser.h" #include "core/resources/editablecourseresource.h" -#include "../mocks/languagestub.h" -#include "../mocks/coursestub.h" +#include "core/unit.h" +#include "resourcerepositorystub.h" -#include -#include #include -#include -#include -#include +#include #include +#include +#include +#include +#include #include #include -#include +#include TestEditableCourseResource::TestEditableCourseResource() { } void TestEditableCourseResource::init() { } void TestEditableCourseResource::cleanup() { } void TestEditableCourseResource::loadCourseResource() { std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); auto course = EditableCourseResource::create(QUrl::fromLocalFile(":/courses/de.xml"), &repository); QCOMPARE(course->file().toLocalFile(), ":/courses/de.xml"); QCOMPARE(course->id(), "de"); QCOMPARE(course->foreignId(), "artikulate-basic"); QCOMPARE(course->title(), "Artikulate Deutsch"); QCOMPARE(course->description(), "Ein Kurs in (hoch-)deutscher Aussprache."); QVERIFY(course->language() != nullptr); QCOMPARE(course->language()->id(), "de"); QCOMPARE(course->units().count(), 1); QCOMPARE(course->units().first()->course(), course); const auto unit = course->units().first(); QVERIFY(unit != nullptr); QCOMPARE(unit->id(), "1"); QCOMPARE(unit->title(), QStringLiteral("Auf der Straße")); QCOMPARE(unit->foreignId(), "{dd60f04a-eb37-44b7-9787-67aaf7d3578d}"); QCOMPARE(unit->course(), course); QCOMPARE(unit->phrases().count(), 3); // note: this test takes the silent assumption that phrases are added to the list in same // order as they are defined in the file. This assumption should be made explicit or dropped const auto firstPhrase = unit->phrases().first(); QVERIFY(firstPhrase != nullptr); QCOMPARE(firstPhrase->id(), "1"); QCOMPARE(firstPhrase->foreignId(), "{3a4c1926-60d7-44c6-80d1-03165a641c75}"); QCOMPARE(firstPhrase->text(), "Guten Tag."); QCOMPARE(firstPhrase->soundFileUrl(), ":/courses/de_01.ogg"); QCOMPARE(firstPhrase->type(), Phrase::Type::Sentence); QVERIFY(firstPhrase->phonemes().isEmpty()); } void TestEditableCourseResource::unitAddAndRemoveHandling() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); auto course = EditableCourseResource::create(QUrl::fromLocalFile(":/courses/de.xml"), &repository); // begin of test auto unit = Unit::create(); unit->setId("testunit"); const int initialUnitNumber = course->units().count(); QCOMPARE(initialUnitNumber, 1); QSignalSpy spyAboutToBeAdded(course.get(), SIGNAL(unitAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(course.get(), SIGNAL(unitAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); auto sharedUnit = course->addUnit(std::move(unit)); QCOMPARE(course->units().count(), initialUnitNumber + 1); QCOMPARE(spyAboutToBeAdded.count(), 1); QCOMPARE(spyAdded.count(), 1); QCOMPARE(sharedUnit->course(), course); } void TestEditableCourseResource::coursePropertyChanges() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); auto course = CourseResource::create(QUrl::fromLocalFile(":/courses/de.xml"), &repository); // id { const QString value = "newId"; QSignalSpy spy(course.get(), SIGNAL(idChanged())); QCOMPARE(spy.count(), 0); course->setId(value); QCOMPARE(course->id(), value); QCOMPARE(spy.count(), 1); } // foreign id { const QString value = "newForeignId"; QSignalSpy spy(course.get(), SIGNAL(foreignIdChanged())); QCOMPARE(spy.count(), 0); course->setForeignId(value); QCOMPARE(course->foreignId(), value); QCOMPARE(spy.count(), 1); } // title { const QString value = "newTitle"; QSignalSpy spy(course.get(), SIGNAL(titleChanged())); QCOMPARE(spy.count(), 0); course->setTitle(value); QCOMPARE(course->title(), value); QCOMPARE(spy.count(), 1); } // title { const QString value = "newI18nTitle"; QSignalSpy spy(course.get(), SIGNAL(i18nTitleChanged())); QCOMPARE(spy.count(), 0); course->setI18nTitle(value); QCOMPARE(course->i18nTitle(), value); QCOMPARE(spy.count(), 1); } // description { const QString value = "newDescription"; QSignalSpy spy(course.get(), SIGNAL(descriptionChanged())); QCOMPARE(spy.count(), 0); course->setDescription(value); QCOMPARE(course->description(), value); QCOMPARE(spy.count(), 1); } // language { std::shared_ptr testLanguage; QSignalSpy spy(course.get(), SIGNAL(languageChanged())); QCOMPARE(spy.count(), 0); course->setLanguage(testLanguage); QCOMPARE(course->language(), testLanguage); QCOMPARE(spy.count(), 1); } } void TestEditableCourseResource::fileLoadSaveCompleteness() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); auto course = EditableCourseResource::create(QUrl::fromLocalFile(":/courses/de.xml"), &repository); QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); // note: this only works, since the resource manager not checks uniqueness of course ids! auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); // test that we actually call the different files QVERIFY(course->file().toLocalFile() != loadedCourse->file().toLocalFile()); QVERIFY(course->id() == loadedCourse->id()); QVERIFY(course->foreignId() == loadedCourse->foreignId()); QVERIFY(course->title() == loadedCourse->title()); QVERIFY(course->description() == loadedCourse->description()); QVERIFY(course->language()->id() == loadedCourse->language()->id()); QCOMPARE(loadedCourse->units().count(), course->units().count()); auto testUnit = course->units().constFirst(); auto compareUnit = loadedCourse->units().constFirst(); QCOMPARE(compareUnit->id(), testUnit->id()); QCOMPARE(compareUnit->foreignId(), testUnit->foreignId()); - QCOMPARE( compareUnit->title(), testUnit->title()); + QCOMPARE(compareUnit->title(), testUnit->title()); QCOMPARE(compareUnit->phrases().count(), testUnit->phrases().count()); std::shared_ptr testPhrase = testUnit->phrases().constFirst(); std::shared_ptr comparePhrase = Phrase::create(); // note that this actually means that we DO NOT respect phrase orders by list order for (const auto &phrase : compareUnit->phrases()) { if (testPhrase->id() == phrase->id()) { comparePhrase = phrase; break; } } QVERIFY(testPhrase->id() == comparePhrase->id()); QVERIFY(testPhrase->foreignId() == comparePhrase->foreignId()); QVERIFY(testPhrase->text() == comparePhrase->text()); QVERIFY(testPhrase->type() == comparePhrase->type()); QVERIFY(testPhrase->sound().fileName() == comparePhrase->sound().fileName()); QVERIFY(testPhrase->phonemes().count() == comparePhrase->phonemes().count()); } void TestEditableCourseResource::modifiedStatus() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); auto course = EditableCourseResource::create(QUrl::fromLocalFile(":/courses/de.xml"), &repository); { // initial file loading QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); } { // set ID QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); loadedCourse->setId("ASDF"); QCOMPARE(loadedCourse->isModified(), true); loadedCourse->sync(); QCOMPARE(loadedCourse->isModified(), false); } { // set title QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); loadedCourse->setTitle("ASDF"); QCOMPARE(loadedCourse->isModified(), true); loadedCourse->sync(); QCOMPARE(loadedCourse->isModified(), false); } { // set i18n title QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); loadedCourse->setI18nTitle("ASDF"); QCOMPARE(loadedCourse->isModified(), true); loadedCourse->sync(); QCOMPARE(loadedCourse->isModified(), false); } { // set description QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); loadedCourse->setDescription("ASDF"); QCOMPARE(loadedCourse->isModified(), true); loadedCourse->sync(); QCOMPARE(loadedCourse->isModified(), false); } { // set language QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); std::shared_ptr newLanguage(new LanguageStub("en")); loadedCourse->setLanguage(newLanguage); QCOMPARE(loadedCourse->isModified(), true); loadedCourse->sync(); QCOMPARE(loadedCourse->isModified(), false); } { // add unit QTemporaryFile outputFile; outputFile.open(); course->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); auto loadedCourse = EditableCourseResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); QCOMPARE(loadedCourse->isModified(), false); auto unit = Unit::create(); unit->setId("testunit"); loadedCourse->addUnit(std::move(unit)); QCOMPARE(loadedCourse->isModified(), true); loadedCourse->sync(); QCOMPARE(loadedCourse->isModified(), false); } } void TestEditableCourseResource::skeletonUpdate() { std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); auto course = EditableCourseResource::create(QUrl::fromLocalFile(":/courses/de.xml"), &repository); QCOMPARE(course->units().count(), 1); // create skeleton stub auto importPhrase = Phrase::create(); importPhrase->setId("importPhraseId"); importPhrase->setText("phraseText"); importPhrase->setType(IPhrase::Type::Sentence); auto importUnit = Unit::create(); importUnit->setId("importId"); importUnit->addPhrase(importPhrase); auto skeleton = CourseStub::create(language, {importUnit}); // test import course->updateFrom(skeleton); QCOMPARE(course->units().count(), 2); { std::shared_ptr importedUnit; for (auto unit : course->units()) { if (unit->foreignId() == importUnit->id()) { importedUnit = unit; break; } } QVERIFY(importedUnit != nullptr); QCOMPARE(importedUnit->foreignId(), importUnit->id()); QCOMPARE(importedUnit->id(), importUnit->id()); QCOMPARE(importedUnit->title(), importUnit->title()); QCOMPARE(importedUnit->phrases().count(), 1); auto importedPhrase = importedUnit->phrases().first(); QCOMPARE(importedPhrase->id(), importPhrase->id()); QCOMPARE(importedPhrase->foreignId(), importPhrase->id()); QCOMPARE(importedPhrase->text(), importPhrase->text()); QCOMPARE(importedPhrase->type(), importPhrase->type()); } // test that re-import does not change course course->updateFrom(skeleton); QCOMPARE(course->units().count(), 2); } QTEST_GUILESS_MAIN(TestEditableCourseResource) diff --git a/autotests/unittests/editorsession/test_editorsession.cpp b/autotests/unittests/editorsession/test_editorsession.cpp index efd9cf8..d33477f 100644 --- a/autotests/unittests/editorsession/test_editorsession.cpp +++ b/autotests/unittests/editorsession/test_editorsession.cpp @@ -1,225 +1,224 @@ /* * Copyright 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 "test_editorsession.h" +#include "../mocks/editablecoursestub.h" +#include "../mocks/languagestub.h" #include "editablerepositorystub.h" #include "src/core/editorsession.h" #include "src/core/icourse.h" #include "src/core/ieditablecourse.h" #include "src/core/ieditablerepository.h" #include "src/core/language.h" #include "src/core/resources/skeletonresource.h" #include "src/core/unit.h" -#include "../mocks/editablecoursestub.h" -#include "../mocks/languagestub.h" -#include #include +#include void TestEditorSession::init() { // no initialization of test case } void TestEditorSession::cleanup() { // no cleanup after test run } void TestEditorSession::createEditorSession() { auto languageGerman = std::make_shared("de"); auto languageEnglish = std::make_shared("en"); std::shared_ptr course = EditableCourseStub::create(languageGerman, QVector>()); course->setLanguage(languageGerman); auto skeleton = SkeletonResource::create(QUrl(), nullptr); - EditableRepositoryStub repository{ + EditableRepositoryStub repository { {languageGerman, languageEnglish}, // languages - {skeleton}, // skeletons - {course} // courses + {skeleton}, // skeletons + {course} // courses }; EditorSession session; session.setRepository(&repository); QVERIFY(session.course() == nullptr); QVERIFY(session.language() == nullptr); } void TestEditorSession::nonSkeletonSwitchingBehavior() { auto languageGerman = std::make_shared("de"); auto languageEnglish = std::make_shared("en"); std::shared_ptr courseGerman = EditableCourseStub::create(languageGerman, QVector>()); courseGerman->setId("course-german"); std::shared_ptr courseEnglish = EditableCourseStub::create(languageEnglish, QVector>()); courseEnglish->setId("course-english"); - EditableRepositoryStub repository{ + EditableRepositoryStub repository { {languageGerman, languageEnglish}, // languages - {}, // skeletons - {courseGerman, courseEnglish} // courses + {}, // skeletons + {courseGerman, courseEnglish} // courses }; EditorSession session; session.setRepository(&repository); QVERIFY(session.course() == nullptr); session.setCourse(courseGerman.get()); QCOMPARE(session.course()->id(), courseGerman->id()); QVERIFY(session.language() != nullptr); QCOMPARE(session.language()->id(), languageGerman->id()); QVERIFY(session.language() != nullptr); QCOMPARE(session.language()->id(), languageGerman->id()); session.setCourse(courseEnglish.get()); QVERIFY(session.course() != nullptr); QCOMPARE(session.course()->id(), courseEnglish->id()); QVERIFY(session.language() != nullptr); QCOMPARE(session.language()->id(), languageEnglish->id()); - } void TestEditorSession::skeletonSwitchingBehavior() { auto languageGerman = std::make_shared("de"); auto languageEnglish = std::make_shared("en"); std::shared_ptr courseGermanA = EditableCourseStub::create(languageGerman, QVector>()); courseGermanA->setId("course-german"); courseGermanA->setForeignId("testskeletonA"); std::shared_ptr courseGermanB = EditableCourseStub::create(languageGerman, QVector>()); courseGermanB->setId("course-german"); courseGermanB->setForeignId("testskeletonB"); std::shared_ptr courseEnglishA = EditableCourseStub::create(languageEnglish, QVector>()); courseEnglishA->setId("course-english"); courseEnglishA->setForeignId("testskeletonA"); auto skeletonA = SkeletonResource::create(QUrl(), nullptr); skeletonA->setId("testskeletonA"); auto skeletonB = SkeletonResource::create(QUrl(), nullptr); skeletonB->setId("testskeletonB"); - EditableRepositoryStub repository{ - {languageGerman, languageEnglish}, // languages - {skeletonA, skeletonB}, // skeletons + EditableRepositoryStub repository { + {languageGerman, languageEnglish}, // languages + {skeletonA, skeletonB}, // skeletons {courseGermanA, courseEnglishA, courseGermanB} // courses }; EditorSession session; session.setRepository(&repository); Q_ASSERT(session.course() != nullptr); QCOMPARE(session.course()->id(), courseGermanA->id()); session.setCourse(courseEnglishA.get()); Q_ASSERT(session.course() != nullptr); QCOMPARE(session.course()->id(), courseEnglishA->id()); session.setCourse(courseGermanB.get()); QVERIFY(session.course() != nullptr); QCOMPARE(session.course()->id(), courseGermanB->id()); QVERIFY(session.language() != nullptr); QCOMPARE(session.language()->id(), languageGerman->id()); } void TestEditorSession::iterateCourse() { // language auto language = std::make_shared("de"); // course auto unitA = Unit::create(); auto unitB = Unit::create(); std::shared_ptr phraseA1 = Phrase::create(); std::shared_ptr phraseA2 = Phrase::create(); std::shared_ptr phraseB1 = Phrase::create(); std::shared_ptr phraseB2 = Phrase::create(); // note: phrases without soundfiles are skipped in session generation phraseA1->setId("A1"); phraseA2->setId("A2"); phraseB1->setId("B1"); phraseB2->setId("B2"); phraseA1->setSound(QUrl::fromLocalFile("/tmp/a1.ogg")); phraseA2->setSound(QUrl::fromLocalFile("/tmp/a1.ogg")); phraseB1->setSound(QUrl::fromLocalFile("/tmp/b1.ogg")); phraseB2->setSound(QUrl::fromLocalFile("/tmp/b2.ogg")); unitA->addPhrase(phraseA1); unitA->addPhrase(phraseA2); unitB->addPhrase(phraseB1); unitB->addPhrase(phraseB2); auto course = EditableCourseStub::create(language, QVector>({unitA, unitB})); - EditableRepositoryStub repository{ + EditableRepositoryStub repository { {language}, // languages - {}, // skeletons - {course} // courses + {}, // skeletons + {course} // courses }; EditorSession session; session.setRepository(&repository); session.setCourse(course.get()); // session assumed to initialize with first units's first phrase QCOMPARE(session.activeUnit(), unitA.get()); QCOMPARE(session.activePhrase()->self(), phraseA1); QVERIFY(course.get() == session.course()); // test direct unit setters session.setActiveUnit(unitA.get()); QCOMPARE(session.activeUnit()->self(), unitA); session.setActiveUnit(unitB.get()); QCOMPARE(session.activeUnit()->self(), unitB); // test direct phrase setters session.setActivePhrase(phraseA1.get()); QCOMPARE(session.activePhrase()->self(), phraseA1); QCOMPARE(session.activeUnit()->self(), unitA); session.setActivePhrase(phraseB1.get()); QCOMPARE(session.activePhrase()->self(), phraseB1); QCOMPARE(session.activeUnit()->self(), unitB); // test phrase forward iterators session.setActivePhrase(phraseA1.get()); QCOMPARE(session.activeUnit()->self(), unitA); QCOMPARE(session.activePhrase()->id(), phraseA1->id()); QVERIFY(session.hasNextPhrase()); session.switchToNextPhrase(); QCOMPARE(session.activeUnit()->self(), unitA); QCOMPARE(session.activePhrase()->id(), phraseA2->id()); session.switchToNextPhrase(); QCOMPARE(session.activePhrase()->self(), phraseB1); session.switchToNextPhrase(); QCOMPARE(session.activePhrase()->self(), phraseB2); QVERIFY(!session.hasNextPhrase()); // at the end, do not iterate further session.switchToNextPhrase(); QCOMPARE(session.activePhrase()->self(), phraseB2); // test phrase backward iterators QVERIFY(session.hasPreviousPhrase()); session.switchToPreviousPhrase(); QCOMPARE(session.activePhrase()->self(), phraseB1); session.switchToPreviousPhrase(); QCOMPARE(session.activePhrase()->id(), phraseA2->id()); session.switchToPreviousPhrase(); QCOMPARE(session.activePhrase()->id(), phraseA1->id()); QVERIFY(!session.hasPreviousPhrase()); // at the end, do not iterate further session.switchToPreviousPhrase(); QCOMPARE(session.activePhrase()->id(), phraseA1->id()); } QTEST_GUILESS_MAIN(TestEditorSession) diff --git a/autotests/unittests/editorsession/test_editorsession.h b/autotests/unittests/editorsession/test_editorsession.h index 99c0dd5..6d12c9f 100644 --- a/autotests/unittests/editorsession/test_editorsession.h +++ b/autotests/unittests/editorsession/test_editorsession.h @@ -1,65 +1,65 @@ /* * Copyright 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 TEST_EDITORSESSION_H #define TEST_EDITORSESSION_H #include class TestEditorSession : public QObject { Q_OBJECT public: TestEditorSession() = default; private Q_SLOTS: /** * Called before every test case. */ void init(); /** * Called after every test case. */ void cleanup(); - /** - * @brief Construct and destruct editor session and test initial values - */ - void createEditorSession(); + /** + * @brief Construct and destruct editor session and test initial values + */ + void createEditorSession(); - /** - * @brief Test switching behavior for courses without skeleton. - */ - void nonSkeletonSwitchingBehavior(); + /** + * @brief Test switching behavior for courses without skeleton. + */ + void nonSkeletonSwitchingBehavior(); - /** - * @brief Test handling of skeletons and respective course switching - */ - void skeletonSwitchingBehavior(); + /** + * @brief Test handling of skeletons and respective course switching + */ + void skeletonSwitchingBehavior(); - /** - * @brief Test for all iterator functionality - */ - void iterateCourse(); + /** + * @brief Test for all iterator functionality + */ + void iterateCourse(); }; #endif diff --git a/autotests/unittests/resourcerepository/test_resourcerepository.cpp b/autotests/unittests/resourcerepository/test_resourcerepository.cpp index f6ad9ea..c9928fe 100644 --- a/autotests/unittests/resourcerepository/test_resourcerepository.cpp +++ b/autotests/unittests/resourcerepository/test_resourcerepository.cpp @@ -1,89 +1,89 @@ /* * Copyright 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 "test_resourcerepository.h" -#include -#include -#include -#include "src/core/resourcerepository.h" #include "src/core/language.h" +#include "src/core/resourcerepository.h" +#include +#include +#include TestResourceRepository::TestResourceRepository() : m_repositoryLocation(QUrl::fromLocalFile(qApp->applicationDirPath() + "/../autotests/unittests/data/")) { } void TestResourceRepository::init() { // check that test data is deployed at the expected location QVERIFY(QFile::exists(m_repositoryLocation.toLocalFile() + "/courses/de/de.xml")); QVERIFY(QFile::exists(m_repositoryLocation.toLocalFile() + "/courses/fr/fr.xml")); } void TestResourceRepository::cleanup() { // TODO cleanup after test run } void TestResourceRepository::createRepository() { ResourceRepository repository(QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/courses/")); QCOMPARE(repository.storageLocation(), QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/courses/")); repository.reloadCourses(); QCOMPARE(repository.courses().count(), 2); } void TestResourceRepository::iResourceRepositoryCompatability() { ResourceRepository repository(QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/courses/")); IResourceRepository *interface = &repository; QCOMPARE(interface->storageLocation(), QUrl::fromLocalFile(m_repositoryLocation.toLocalFile() + "/courses/")); QVERIFY(interface->languages().count() > 0); QCOMPARE(interface->courses().count(), 0); // test adding QSignalSpy spyAboutToBeAdded(dynamic_cast(interface), SIGNAL(courseAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(dynamic_cast(interface), SIGNAL(courseAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); repository.reloadCourses(); QCOMPARE(interface->courses().count(), 2); QCOMPARE(spyAboutToBeAdded.count(), 2); QCOMPARE(spyAdded.count(), 2); // test removal // note: repository does not provide removal of courses, yet // test access of courses grouped by language auto languages = interface->languages(); std::shared_ptr german; for (auto language : interface->languages()) { if (language->id() == "de") { german = language; break; } } - QVERIFY(german != nullptr); // ensure that German language was found + QVERIFY(german != nullptr); // ensure that German language was found QCOMPARE(interface->courses(german->id()).count(), 1); // there is exactly one German course - QCOMPARE(interface->courses(nullptr).count(), 2); // all courses in total are 2 + QCOMPARE(interface->courses(nullptr).count(), 2); // all courses in total are 2 } QTEST_GUILESS_MAIN(TestResourceRepository) diff --git a/autotests/unittests/skeletonmodel/test_skeletonmodel.cpp b/autotests/unittests/skeletonmodel/test_skeletonmodel.cpp index fc19790..35d50b7 100644 --- a/autotests/unittests/skeletonmodel/test_skeletonmodel.cpp +++ b/autotests/unittests/skeletonmodel/test_skeletonmodel.cpp @@ -1,128 +1,128 @@ /* * Copyright 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 "test_skeletonmodel.h" +#include "../mocks/editablecoursestub.h" +#include "../mocks/editablerepositorystub.h" +#include "../mocks/languagestub.h" #include "src/core/icourse.h" #include "src/core/language.h" #include "src/models/skeletonmodel.h" -#include "../mocks/editablerepositorystub.h" -#include "../mocks/editablecoursestub.h" -#include "../mocks/languagestub.h" -#include #include +#include void TestSkeletonModel::init() { // no initialization of test case } void TestSkeletonModel::cleanup() { // no cleanup after test run } void TestSkeletonModel::testInit() { - // boilerplate - std::shared_ptr language(new LanguageStub("de")); - std::vector> languages; - languages.push_back(language); - auto skeleton = EditableCourseStub::create(language, QVector>({})); - EditableRepositoryStub repository(languages, {skeleton}, {}); - - // test initialization - SkeletonModel model(&repository); - QVERIFY(model.resourceRepository() == &repository); - QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.skeleton(0).value(), skeleton.get()); + // boilerplate + std::shared_ptr language(new LanguageStub("de")); + std::vector> languages; + languages.push_back(language); + auto skeleton = EditableCourseStub::create(language, QVector>({})); + EditableRepositoryStub repository(languages, {skeleton}, {}); + + // test initialization + SkeletonModel model(&repository); + QVERIFY(model.resourceRepository() == &repository); + QCOMPARE(model.rowCount(), 1); + QCOMPARE(model.skeleton(0).value(), skeleton.get()); } void TestSkeletonModel::testAddRemoveOperations() { // boilerplate std::shared_ptr language(new LanguageStub("de")); std::vector> languages; languages.push_back(language); EditableRepositoryStub repository(languages, {}, {}); // test initialization SkeletonModel model(&repository); QVERIFY(model.resourceRepository() == &repository); QCOMPARE(model.rowCount(), 0); auto skeleton = EditableCourseStub::create(language, QVector>({})); { // add skeleton - QSignalSpy spyAboutToBeAdded(&repository, SIGNAL(skeletonAboutToBeAdded(std::shared_ptr,int))); + QSignalSpy spyAboutToBeAdded(&repository, SIGNAL(skeletonAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(&repository, SIGNAL(skeletonAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); repository.appendSkeleton(skeleton); QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.skeleton(0).value(), skeleton.get()); + QCOMPARE(model.skeleton(0).value(), skeleton.get()); QCOMPARE(spyAboutToBeAdded.count(), 1); QCOMPARE(spyAdded.count(), 1); } - { // remove skeleton - QSignalSpy spyAboutToBeRemoved(&repository, SIGNAL(skeletonAboutToBeRemoved(int))); - QSignalSpy spyRemoved(&repository, SIGNAL(skeletonRemoved())); - QCOMPARE(spyAboutToBeRemoved.count(), 0); - QCOMPARE(spyRemoved.count(), 0); - repository.removeSkeleton(skeleton); - QCOMPARE(model.rowCount(), 0); - QCOMPARE(spyAboutToBeRemoved.count(), 1); - QCOMPARE(spyRemoved.count(), 1); - } + { // remove skeleton + QSignalSpy spyAboutToBeRemoved(&repository, SIGNAL(skeletonAboutToBeRemoved(int))); + QSignalSpy spyRemoved(&repository, SIGNAL(skeletonRemoved())); + QCOMPARE(spyAboutToBeRemoved.count(), 0); + QCOMPARE(spyRemoved.count(), 0); + repository.removeSkeleton(skeleton); + QCOMPARE(model.rowCount(), 0); + QCOMPARE(spyAboutToBeRemoved.count(), 1); + QCOMPARE(spyRemoved.count(), 1); + } } void TestSkeletonModel::testDataChangedSignals() { // boilerplate std::shared_ptr language(new LanguageStub("de")); std::vector> languages; languages.push_back(language); auto skeleton = EditableCourseStub::create(language, QVector>({})); EditableRepositoryStub repository(languages, {skeleton}, {}); // test initialization SkeletonModel model(&repository); QVERIFY(model.resourceRepository() == &repository); QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.skeleton(0).value(), skeleton.get()); + QCOMPARE(model.skeleton(0).value(), skeleton.get()); { // test adding of connections - QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &,const QModelIndex &, const QVector))); + QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector))); QCOMPARE(spyUpdate.count(), 0); std::static_pointer_cast(skeleton)->setTitle("TitleSwitched"); QCOMPARE(spyUpdate.count(), 1); } { // test removal of connections - QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &,const QModelIndex &, const QVector))); + QSignalSpy spyUpdate(&model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector))); QCOMPARE(spyUpdate.count(), 0); repository.removeSkeleton(skeleton); std::static_pointer_cast(skeleton)->setTitle("TitleSwitchedAgain"); QCOMPARE(spyUpdate.count(), 0); } } QTEST_GUILESS_MAIN(TestSkeletonModel) diff --git a/autotests/unittests/skeletonresource/test_skeletonresource.cpp b/autotests/unittests/skeletonresource/test_skeletonresource.cpp index 03547c6..aa53061 100644 --- a/autotests/unittests/skeletonresource/test_skeletonresource.cpp +++ b/autotests/unittests/skeletonresource/test_skeletonresource.cpp @@ -1,204 +1,204 @@ /* * Copyright 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 "test_skeletonresource.h" -#include "resourcerepositorystub.h" +#include "../mocks/languagestub.h" #include "core/language.h" -#include "core/unit.h" #include "core/phrase.h" #include "core/resources/skeletonresource.h" -#include "../mocks/languagestub.h" +#include "core/unit.h" +#include "resourcerepositorystub.h" -#include #include -#include -#include -#include +#include #include +#include +#include +#include +#include #include #include -#include TestSkeletonResource::TestSkeletonResource() { } void TestSkeletonResource::init() { } void TestSkeletonResource::cleanup() { } void TestSkeletonResource::loadSkeletonResource() { std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); const QString courseDirectory = "data/contributorrepository/skeletons/"; const QString courseFile = courseDirectory + "skeleton.xml"; auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository); QCOMPARE(skeleton->file().toLocalFile(), courseFile); QCOMPARE(skeleton->id(), "skeleton-testdata"); QCOMPARE(skeleton->foreignId(), "skeleton-testdata"); // always same as ID QCOMPARE(skeleton->title(), "Artikulate Test Course Title"); QCOMPARE(skeleton->description(), "Artikulate Test Course Description"); QVERIFY(skeleton->language() == nullptr); // a skeleton must not have a language QCOMPARE(skeleton->units().count(), 2); const auto unit = skeleton->units().first(); QVERIFY(unit != nullptr); QCOMPARE(unit->id(), "{11111111-b885-4833-97ff-27cb1ca2f543}"); QCOMPARE(unit->title(), QStringLiteral("Numbers")); QCOMPARE(unit->phrases().count(), 2); QVERIFY(unit->course() != nullptr); QCOMPARE(unit->course().get(), skeleton.get()); // note: this test takes the silent assumption that phrases are added to the list in same // order as they are defined in the file. This assumption should be made explicit or dropped const auto firstPhrase = unit->phrases().first(); QVERIFY(firstPhrase != nullptr); QCOMPARE(firstPhrase->id(), "{22222222-9234-4da5-a6fe-dbd5104f57d5}"); QCOMPARE(firstPhrase->text(), "0"); QCOMPARE(firstPhrase->type(), Phrase::Type::Word); const auto secondPhrase = unit->phrases().at(1); QVERIFY(secondPhrase != nullptr); QCOMPARE(secondPhrase->id(), "{333333333-b4a9-4264-9a26-75a55aa5d302}"); QCOMPARE(secondPhrase->text(), "1"); QCOMPARE(secondPhrase->type(), Phrase::Type::Word); } void TestSkeletonResource::unitAddAndRemoveHandling() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); const QString courseDirectory = "data/contributorrepository/skeletons/"; const QString courseFile = courseDirectory + "skeleton.xml"; auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository); // begin of test auto unit = Unit::create(); unit->setId("testunit"); const int initialUnitNumber = skeleton->units().count(); QCOMPARE(initialUnitNumber, 2); QSignalSpy spyAboutToBeAdded(skeleton.get(), SIGNAL(unitAboutToBeAdded(std::shared_ptr, int))); QSignalSpy spyAdded(skeleton.get(), SIGNAL(unitAdded())); QCOMPARE(spyAboutToBeAdded.count(), 0); QCOMPARE(spyAdded.count(), 0); auto sharedUnit = skeleton->addUnit(std::move(unit)); QCOMPARE(skeleton->units().count(), initialUnitNumber + 1); QCOMPARE(spyAboutToBeAdded.count(), 1); QCOMPARE(spyAdded.count(), 1); QCOMPARE(sharedUnit->course(), skeleton); } void TestSkeletonResource::coursePropertyChanges() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); const QString courseDirectory = "data/contributorrepository/skeletons/"; const QString courseFile = courseDirectory + "skeleton.xml"; auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository); // id { const QString value = "newId"; QSignalSpy spy(skeleton.get(), SIGNAL(idChanged())); QCOMPARE(spy.count(), 0); skeleton->setId(value); QCOMPARE(skeleton->id(), value); QCOMPARE(spy.count(), 1); } // title { const QString value = "newTitle"; QSignalSpy spy(skeleton.get(), SIGNAL(titleChanged())); QCOMPARE(spy.count(), 0); skeleton->setTitle(value); QCOMPARE(skeleton->title(), value); QCOMPARE(spy.count(), 1); } // description { const QString value = "newDescription"; QSignalSpy spy(skeleton.get(), SIGNAL(descriptionChanged())); QCOMPARE(spy.count(), 0); skeleton->setDescription(value); QCOMPARE(skeleton->description(), value); QCOMPARE(spy.count(), 1); } } void TestSkeletonResource::fileLoadSaveCompleteness() { // boilerplate std::shared_ptr language(new LanguageStub("de")); ResourceRepositoryStub repository({language}); const QString courseDirectory = "data/contributorrepository/skeletons/"; const QString courseFile = courseDirectory + "skeleton.xml"; auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository); QTemporaryFile outputFile; outputFile.open(); skeleton->exportToFile(QUrl::fromLocalFile(outputFile.fileName())); // note: this only works, since the resource manager not checks uniqueness of course ids! auto loadedSkeleton = SkeletonResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository); // test that we actually call the different files QVERIFY(skeleton->file().toLocalFile() != loadedSkeleton->file().toLocalFile()); QCOMPARE(loadedSkeleton->id(), skeleton->id()); QCOMPARE(loadedSkeleton->foreignId(), skeleton->foreignId()); QCOMPARE(loadedSkeleton->title(), skeleton->title()); QCOMPARE(loadedSkeleton->description(), skeleton->description()); QCOMPARE(loadedSkeleton->language(), skeleton->language()); QCOMPARE(loadedSkeleton->units().count(), skeleton->units().count()); auto testUnit = skeleton->units().constFirst(); auto compareUnit = loadedSkeleton->units().constFirst(); QCOMPARE(testUnit->id(), compareUnit->id()); QCOMPARE(testUnit->foreignId(), compareUnit->foreignId()); QCOMPARE(testUnit->title(), compareUnit->title()); QCOMPARE(testUnit->phrases().count(), compareUnit->phrases().count()); std::shared_ptr testPhrase = testUnit->phrases().constFirst(); std::shared_ptr comparePhrase = Phrase::create(); // note that this actually means that we DO NOT respect phrase orders by list order for (const auto &phrase : compareUnit->phrases()) { if (testPhrase->id() == phrase->id()) { comparePhrase = phrase; break; } } QVERIFY(testPhrase->id() == comparePhrase->id()); QVERIFY(testPhrase->foreignId() == comparePhrase->foreignId()); QVERIFY(testPhrase->text() == comparePhrase->text()); QVERIFY(testPhrase->type() == comparePhrase->type()); QVERIFY(testPhrase->sound().fileName() == comparePhrase->sound().fileName()); QVERIFY(testPhrase->phonemes().count() == comparePhrase->phonemes().count()); } QTEST_GUILESS_MAIN(TestSkeletonResource) diff --git a/autotests/unittests/skeletonresource/test_skeletonresource.h b/autotests/unittests/skeletonresource/test_skeletonresource.h index 81abbf0..52fef1f 100644 --- a/autotests/unittests/skeletonresource/test_skeletonresource.h +++ b/autotests/unittests/skeletonresource/test_skeletonresource.h @@ -1,70 +1,70 @@ /* * 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 . */ #ifndef TESTSKELETONRESOURCE_H #define TESTSKELETONRESOURCE_H #include #include class TestSkeletonResource : public QObject { Q_OBJECT public: TestSkeletonResource(); private slots: /** * @brief Called before every test case. */ void init(); /** * @brief Called after every test case. */ void cleanup(); /** * @brief Test simple loading of course resource XML file */ - void loadSkeletonResource(); + void loadSkeletonResource(); /** * @brief Test handling of unit insertions (specifically, the signals) */ - void unitAddAndRemoveHandling(); + void unitAddAndRemoveHandling(); /** * @brief Test of all course property changes except unit handling */ - void coursePropertyChanges(); + void coursePropertyChanges(); /** * Test if serialization of unserialized file gives original file. * TODO this is a test by only string equality and should improved to test on a data level */ - void fileLoadSaveCompleteness(); + void fileLoadSaveCompleteness(); private: bool m_systemUseCourseRepositoryValue; }; #endif diff --git a/autotests/unittests/trainingsession/test_trainingsession.cpp b/autotests/unittests/trainingsession/test_trainingsession.cpp index 7c018cb..d21cd84 100644 --- a/autotests/unittests/trainingsession/test_trainingsession.cpp +++ b/autotests/unittests/trainingsession/test_trainingsession.cpp @@ -1,207 +1,207 @@ /* * Copyright 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 "test_trainingsession.h" -#include "src/core/trainingsession.h" -#include "src/core/icourse.h" -#include "src/core/language.h" -#include "src/core/unit.h" -#include "src/core/trainingaction.h" #include "../mocks/coursestub.h" #include "../mocks/languagestub.h" #include "liblearnerprofile/src/profilemanager.h" -#include +#include "src/core/icourse.h" +#include "src/core/language.h" +#include "src/core/trainingaction.h" +#include "src/core/trainingsession.h" +#include "src/core/unit.h" #include +#include // assumption: during a training session the units and phrases of a course do not change // any change of such a course shall result in a reload of a training session void TestTrainingSession::init() { // no initialization of test case } void TestTrainingSession::cleanup() { // no cleanup after test run } void TestTrainingSession::createTrainingSessionWithoutUnits() { auto language = std::make_shared("de"); CourseStub course(language, QVector>()); LearnerProfile::ProfileManager manager; TrainingSession session(&manager); session.setCourse(&course); QVERIFY(&course == session.course()); } void TestTrainingSession::createTrainingSessionWithEmptySounds() { auto language = std::make_shared("de"); auto unitA = Unit::create(); auto unitB = Unit::create(); std::shared_ptr phraseA1 = Phrase::create(); std::shared_ptr phraseA2 = Phrase::create(); std::shared_ptr phraseB1 = Phrase::create(); std::shared_ptr phraseB2 = Phrase::create(); // note: phrases without soundfiles are skipped in session generation phraseA1->setId("A1"); phraseA2->setId("A2"); phraseB1->setId("B1"); phraseB2->setId("B2"); phraseA1->setSound(QUrl::fromLocalFile("/tmp/a1.ogg")); unitA->addPhrase(phraseA1); unitA->addPhrase(phraseA2); unitB->addPhrase(phraseB1); unitB->addPhrase(phraseB2); CourseStub course(language, QVector>({unitA, unitB})); LearnerProfile::ProfileManager manager; TrainingSession session(&manager); session.setCourse(&course); // test number of actions auto actions = session.trainingActions(); QCOMPARE(actions.count(), 1); QCOMPARE(actions.at(0)->actions().count(), 1); } void TestTrainingSession::createTrainingSessionWithEmptyUnits() { auto language = std::make_shared("de"); auto unitA = Unit::create(); auto unitB = Unit::create(); CourseStub course(language, QVector>({unitA, unitB})); LearnerProfile::ProfileManager manager; TrainingSession session(&manager); session.setCourse(&course); QVERIFY(&course == session.course()); } void TestTrainingSession::createTrainingSessionWithUnitsAndPhrases() { auto language = std::make_shared("de"); auto unit = Unit::create(); std::shared_ptr firstPhrase = Phrase::create(); std::shared_ptr secondPhrase = Phrase::create(); unit->addPhrase(firstPhrase); unit->addPhrase(secondPhrase); CourseStub course(language, QVector>({unit})); LearnerProfile::ProfileManager manager; TrainingSession session(&manager); session.setCourse(&course); QVERIFY(&course == session.course()); } void TestTrainingSession::iterateCourse() { auto language = std::make_shared("de"); auto unitA = Unit::create(); auto unitB = Unit::create(); std::shared_ptr phraseA1 = Phrase::create(); std::shared_ptr phraseA2 = Phrase::create(); std::shared_ptr phraseB1 = Phrase::create(); std::shared_ptr phraseB2 = Phrase::create(); // note: phrases without soundfiles are skipped in session generation phraseA1->setId("A1"); phraseA2->setId("A2"); phraseB1->setId("B1"); phraseB2->setId("B2"); phraseA1->setSound(QUrl::fromLocalFile("/tmp/a1.ogg")); phraseA2->setSound(QUrl::fromLocalFile("/tmp/a1.ogg")); phraseB1->setSound(QUrl::fromLocalFile("/tmp/b1.ogg")); phraseB2->setSound(QUrl::fromLocalFile("/tmp/b2.ogg")); unitA->addPhrase(phraseA1); unitA->addPhrase(phraseA2); unitB->addPhrase(phraseB1); unitB->addPhrase(phraseB2); CourseStub course(language, QVector>({unitA, unitB})); LearnerProfile::ProfileManager manager; TrainingSession session(&manager); session.setCourse(&course); // session assumed to initialize with first units's first phrase QCOMPARE(session.activeUnit()->self(), unitA); QCOMPARE(session.activePhrase()->self(), phraseA1); QVERIFY(&course == session.course()); // test direct unit setters session.setUnit(unitA.get()); QCOMPARE(session.activeUnit(), unitA.get()); session.setUnit(unitB.get()); QCOMPARE(session.activeUnit(), unitB.get()); // test direct phrase setters session.setActivePhrase(phraseA1.get()); QCOMPARE(session.activePhrase(), phraseA1.get()); QCOMPARE(session.activeUnit(), unitA.get()); session.setActivePhrase(phraseB1.get()); QCOMPARE(session.activePhrase(), phraseB1.get()); QCOMPARE(session.activeUnit(), unitB.get()); // test number of actions auto actions = session.trainingActions(); QCOMPARE(actions.count(), 2); QCOMPARE(actions.at(0)->actions().count(), 2); QCOMPARE(actions.at(1)->actions().count(), 2); // test phrase iterators: accept iterator session.setActivePhrase(phraseA1.get()); QCOMPARE(session.activeUnit(), unitA.get()); QCOMPARE(session.activePhrase(), phraseA1.get()); QVERIFY(session.hasNext()); session.accept(); QCOMPARE(session.activeUnit(), unitA.get()); QCOMPARE(session.activePhrase(), phraseA2.get()); session.accept(); QCOMPARE(session.activePhrase(), phraseB1.get()); session.accept(); QCOMPARE(session.activePhrase(), phraseB2.get()); QVERIFY(!session.hasNext()); // test phrase iterators: skip iterator session.setActivePhrase(phraseA1.get()); QCOMPARE(session.activeUnit(), unitA.get()); QCOMPARE(session.activePhrase(), phraseA1.get()); QVERIFY(!session.hasPrevious()); QVERIFY(session.hasNext()); session.skip(); QCOMPARE(session.activeUnit(), unitA.get()); QCOMPARE(session.activePhrase(), phraseA2.get()); session.skip(); QCOMPARE(session.activePhrase(), phraseB1.get()); session.skip(); QCOMPARE(session.activePhrase(), phraseB2.get()); QVERIFY(session.hasPrevious()); QVERIFY(!session.hasNext()); // test completed signal QSignalSpy spy(&session, SIGNAL(completed())); session.setActivePhrase(phraseB1.get()); session.accept(); QCOMPARE(spy.count(), 0); session.accept(); QCOMPARE(spy.count(), 1); } QTEST_GUILESS_MAIN(TestTrainingSession) diff --git a/liblearnerprofile/autotests/testlearnerstorage.cpp b/liblearnerprofile/autotests/testlearnerstorage.cpp index ba1e20c..f0a077d 100644 --- a/liblearnerprofile/autotests/testlearnerstorage.cpp +++ b/liblearnerprofile/autotests/testlearnerstorage.cpp @@ -1,120 +1,118 @@ /* * Copyright 2016 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 "testlearnerstorage.h" #include "learner.h" #include "learninggoal.h" #include "storage.h" -#include #include +#include using namespace LearnerProfile; TestLearnerStorage::TestLearnerStorage() : m_storage(nullptr) { - } void TestLearnerStorage::init() { QVERIFY(m_db.open()); m_storage.reset(new Storage(m_db.fileName(), nullptr)); } void TestLearnerStorage::cleanup() { m_db.close(); } void TestLearnerStorage::testLearnerStorage() { LearningGoal tmpGoal(LearningGoal::Language, QStringLiteral("testgoalid"), nullptr); tmpGoal.setName(QStringLiteral("testgoalname")); Learner tmpLearner; tmpLearner.addGoal(&tmpGoal); tmpLearner.setName(QStringLiteral("tester")); QVERIFY(m_storage->storeGoal(&tmpGoal)); QVERIFY(m_storage->storeProfile(&tmpLearner)); - QList< LearnerProfile::LearningGoal* > loadedGoals = m_storage->loadGoals(); + QList loadedGoals = m_storage->loadGoals(); QCOMPARE(loadedGoals.size(), 1); QCOMPARE(loadedGoals.first()->category(), tmpGoal.category()); QCOMPARE(loadedGoals.first()->identifier(), tmpGoal.identifier()); QCOMPARE(loadedGoals.first()->name(), tmpGoal.name()); - QList loadedLearner = m_storage->loadProfiles(loadedGoals); + QList loadedLearner = m_storage->loadProfiles(loadedGoals); QCOMPARE(loadedLearner.size(), 1); QCOMPARE(loadedLearner.first()->identifier(), tmpLearner.identifier()); QCOMPARE(loadedLearner.first()->name(), tmpLearner.name()); QCOMPARE(loadedLearner.first()->goals().size(), 1); - QCOMPARE(loadedLearner.first()->goals().first()->identifier(), - tmpGoal.identifier()); + QCOMPARE(loadedLearner.first()->goals().first()->identifier(), tmpGoal.identifier()); } void TestLearnerStorage::testProgressLogStorage() { LearningGoal tmpGoal(LearningGoal::Language, QStringLiteral("testgoalid"), nullptr); tmpGoal.setName(QStringLiteral("testgoalname")); Learner tmpLearner; tmpLearner.addGoal(&tmpGoal); tmpLearner.setName(QStringLiteral("tester")); QVERIFY(m_storage->storeGoal(&tmpGoal)); QVERIFY(m_storage->storeProfile(&tmpLearner)); - const QDateTime time{QDateTime::currentDateTime()}; + const QDateTime time {QDateTime::currentDateTime()}; QVERIFY(m_storage->storeProgressLog(&tmpLearner, &tmpGoal, "container", "item", 1, time)); auto data = m_storage->readProgressLog(&tmpLearner, &tmpGoal, QStringLiteral("container"), QStringLiteral("item")); QCOMPARE(data.size(), 1); QCOMPARE(data.first().first.toString(Qt::ISODate), time.toString(Qt::ISODate)); } void TestLearnerStorage::testProgressValueStorage() { LearningGoal tmpGoal(LearningGoal::Language, QStringLiteral("testgoalid"), nullptr); tmpGoal.setName(QStringLiteral("testgoalname")); Learner tmpLearner; tmpLearner.addGoal(&tmpGoal); tmpLearner.setName(QStringLiteral("tester")); QVERIFY(m_storage->storeGoal(&tmpGoal)); QVERIFY(m_storage->storeProfile(&tmpLearner)); // insert QVERIFY(m_storage->storeProgressValue(&tmpLearner, &tmpGoal, "container", "itemA", 1)); QVERIFY(m_storage->storeProgressValue(&tmpLearner, &tmpGoal, "container", "itemB", 1)); auto data = m_storage->readProgressValues(&tmpLearner, &tmpGoal, QStringLiteral("container")); QCOMPARE(data.size(), 2); // update QVERIFY(m_storage->storeProgressValue(&tmpLearner, &tmpGoal, "container", "itemA", 2)); data = m_storage->readProgressValues(&tmpLearner, &tmpGoal, QStringLiteral("container")); QCOMPARE(data.find("itemA").value(), 2); QCOMPARE(data.find("itemB").value(), 1); } QTEST_GUILESS_MAIN(TestLearnerStorage) diff --git a/liblearnerprofile/autotests/testlearnerstorage.h b/liblearnerprofile/autotests/testlearnerstorage.h index 3416c26..eca88d3 100644 --- a/liblearnerprofile/autotests/testlearnerstorage.h +++ b/liblearnerprofile/autotests/testlearnerstorage.h @@ -1,59 +1,60 @@ /* * Copyright 2016 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 TESTLEARNERSTORAGE_H #define TESTLEARNERSTORAGE_H #include #include #include -namespace LearnerProfile { - class Storage; +namespace LearnerProfile +{ +class Storage; } class TestLearnerStorage : public QObject { Q_OBJECT public: TestLearnerStorage(); private Q_SLOTS: /** * Called before every test case. */ void init(); /** * Called after every test case. */ void cleanup(); void testLearnerStorage(); void testProgressLogStorage(); void testProgressValueStorage(); private: QScopedPointer m_storage; QTemporaryFile m_db; }; #endif diff --git a/liblearnerprofile/src/learner.cpp b/liblearnerprofile/src/learner.cpp index 579be55..d716555 100644 --- a/liblearnerprofile/src/learner.cpp +++ b/liblearnerprofile/src/learner.cpp @@ -1,204 +1,198 @@ /* * Copyright 2013-2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "learner.h" #include "learner_p.h" #include "learninggoal.h" +#include "liblearner_debug.h" #include -#include #include +#include #include -#include "liblearner_debug.h" using namespace LearnerProfile; Learner::Learner(QObject *parent) : QObject(parent) , d(new LearnerPrivate) { - connect(this, &Learner::goalAdded, - this, &Learner::goalCountChanged); - connect(this, &Learner::goalRemoved, - this, &Learner::goalCountChanged); + connect(this, &Learner::goalAdded, this, &Learner::goalCountChanged); + connect(this, &Learner::goalRemoved, this, &Learner::goalCountChanged); } Learner::~Learner() { - } QString Learner::name() const { return d->m_name; } void Learner::setName(const QString &name) { if (name == d->m_name) { return; } d->m_name = name; emit nameChanged(); } int Learner::identifier() const { return d->m_identifier; } void Learner::setIdentifier(int identifier) { if (identifier == d->m_identifier) { return; } d->m_identifier = identifier; emit identifierChanged(); } QString Learner::imageUrl() const { QString path = d->imagePath(); if (!QFileInfo::exists(path)) { return QString(); } return "file://" + path; } void Learner::clearImage() { const QString path {d->imagePath()}; if (!QFileInfo::exists(path)) { return; } QFile file; if (!file.remove(path)) { qCCritical(LIBLEARNER_LOG) << "could not remove image:" << path; } emit imageChanged(); } void Learner::importImage(const QString &path) { if (!QFileInfo::exists(path)) { qCWarning(LIBLEARNER_LOG) << "image path points to a non-existing file, aborting: " << path; return; } // create image directory if it does not exist QDir dir; if (!dir.exists(d->imageDirectory())) { dir.mkdir(d->imageDirectory()); } QPixmap image = QPixmap(path); image = image.scaled(120, 120); if (!image.save(d->imagePath(), "PNG")) { qCCritical(LIBLEARNER_LOG()) << "could not save scaled image to" << d->imagePath(); } emit imageChanged(); qCDebug(LIBLEARNER_LOG) << "saved scaled image from " << path << " at " << d->imagePath(); } -QList< LearningGoal* > Learner::goals() const +QList Learner::goals() const { return d->m_goals; } void Learner::addGoal(LearnerProfile::LearningGoal *goal) { if (d->m_goals.contains(goal)) { return; } emit goalAboutToBeAdded(goal, d->m_goals.count()); d->m_goals.append(goal); emit goalAdded(); } void Learner::removeGoal(LearnerProfile::LearningGoal *goal) { int index = d->m_goals.indexOf(goal); if (index < 0) { qCritical() << "Cannot remove goal, not found: aborting"; return; } emit goalAboutToBeRemoved(index); d->m_goals.removeAt(index); emit goalRemoved(this, goal); } -bool Learner::hasGoal(LearningGoal* goal) const +bool Learner::hasGoal(LearningGoal *goal) const { foreach (LearningGoal *cmpGoal, d->m_goals) { if (goal->identifier() == cmpGoal->identifier()) { return true; } } return false; } void Learner::setActiveGoal(LearningGoal *goal) { if (d->m_activeGoal.contains(goal->category()) && d->m_activeGoal[goal->category()] == goal) { return; } d->m_activeGoal.insert(goal->category(), goal); emit activeGoalChanged(); } void Learner::setActiveGoal(Learner::Category categoryLearner, const QString &identifier) { // TODO:Qt5 change method parameter to LearningGoal::Category // workaround for Q_INVOKABLE access of enum LearningGoal::Category category = static_cast(categoryLearner); if (d->m_activeGoal.contains(category) && d->m_activeGoal[category]->identifier() == identifier) { return; } foreach (LearningGoal *goal, d->m_goals) { if (goal->category() == category && goal->identifier() == identifier) { setActiveGoal(goal); return; } } - qCritical() << "Could not select learning goal with ID " << identifier - << ": not registered for this learner"; + qCritical() << "Could not select learning goal with ID " << identifier << ": not registered for this learner"; } -LearningGoal * Learner::activeGoal(Learner::Category categoryLearner) const +LearningGoal *Learner::activeGoal(Learner::Category categoryLearner) const { // TODO:Qt5 change method parameter to LearningGoal::Category // workaround for Q_INVOKABLE access of enum LearningGoal::Category category = static_cast(categoryLearner); if (!d->m_activeGoal.contains(category)) { - qCWarning(LIBLEARNER_LOG) << "(Learner " << identifier() << ") No current learning goal set for category " - << category - << " : fall back to first in list"; + qCWarning(LIBLEARNER_LOG) << "(Learner " << identifier() << ") No current learning goal set for category " << category << " : fall back to first in list"; foreach (LearningGoal *goal, d->m_goals) { if (goal->category() == category) { return goal; } } qCWarning(LIBLEARNER_LOG) << "No learning goals of category " << category << " registered"; return nullptr; } return d->m_activeGoal[category]; } diff --git a/liblearnerprofile/src/learner.h b/liblearnerprofile/src/learner.h index db08294..4f4a3e1 100644 --- a/liblearnerprofile/src/learner.h +++ b/liblearnerprofile/src/learner.h @@ -1,97 +1,94 @@ /* * Copyright 2013-2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef LEARNER_H #define LEARNER_H -#include "liblearnerprofile_export.h" #include "learninggoal.h" +#include "liblearnerprofile_export.h" #include namespace LearnerProfile { class LearnerPrivate; class LearningGoal; /** * \class Learner */ class LIBLEARNERPROFILE_EXPORT Learner : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(int id READ identifier WRITE setIdentifier NOTIFY identifierChanged) Q_PROPERTY(QString imageUrl READ imageUrl NOTIFY imageChanged) - Q_PROPERTY(QList goals READ goals NOTIFY goalCountChanged) + Q_PROPERTY(QList goals READ goals NOTIFY goalCountChanged) public: // TODO workaround for QT-BUG-26415, fixed in Qt5.0 // we must simulate the LearningGoal::Category enum in Learner to be able to allow its usage // as parameter for Q_INVOKABLE method // can be removed with Qt 5.0 migration Q_ENUMS(Category) - enum Category { - Unspecified = 0, - Language = 1 - }; + enum Category { Unspecified = 0, Language = 1 }; explicit Learner(QObject *parent = nullptr); ~Learner(); QString name() const; void setName(const QString &name); /** * \return URL to image * \note since it is a local file the path begins with "file://" */ QString imageUrl() const; Q_INVOKABLE void clearImage(); void importImage(const QString &path); int identifier() const; void setIdentifier(int identifier); /** * \return list of all learning goals of learner */ QList goals() const; Q_INVOKABLE void addGoal(LearnerProfile::LearningGoal *goal); Q_INVOKABLE void removeGoal(LearnerProfile::LearningGoal *goal); Q_INVOKABLE bool hasGoal(LearnerProfile::LearningGoal *goal) const; void setActiveGoal(LearnerProfile::LearningGoal *goal); Q_INVOKABLE void setActiveGoal(LearnerProfile::Learner::Category category, const QString &identifier); - Q_INVOKABLE LearnerProfile::LearningGoal * activeGoal(LearnerProfile::Learner::Category category) const; + Q_INVOKABLE LearnerProfile::LearningGoal *activeGoal(LearnerProfile::Learner::Category category) const; Q_SIGNALS: void nameChanged(); void imageChanged(); void identifierChanged(); - void goalAboutToBeAdded(LearningGoal*,int); + void goalAboutToBeAdded(LearningGoal *, int); void goalAdded(); void goalAboutToBeRemoved(int); - void goalRemoved(Learner*, LearningGoal*); + void goalRemoved(Learner *, LearningGoal *); void goalCountChanged(); void activeGoalChanged(); private: Q_DISABLE_COPY(Learner) const QScopedPointer d; }; } #endif // LEARNER_H diff --git a/liblearnerprofile/src/learner_p.h b/liblearnerprofile/src/learner_p.h index 5af9aed..950a4e9 100644 --- a/liblearnerprofile/src/learner_p.h +++ b/liblearnerprofile/src/learner_p.h @@ -1,65 +1,64 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef LEARNER_P_H #define LEARNER_P_H -#include -#include -#include -#include #include "learninggoal.h" #include +#include +#include +#include +#include namespace LearnerProfile { class LearningGoal; -class LearnerPrivate { - +class LearnerPrivate +{ public: LearnerPrivate() : m_name(QString()) , m_identifier(-1) { } - ~LearnerPrivate() {} + ~LearnerPrivate() + { + } QString imagePath() const { const QString name = QStringLiteral("learner%1.png").arg(m_identifier); return imageDirectory() + name; } QString imageDirectory() const { - return QStandardPaths::writableLocation(QStandardPaths::DataLocation) - + QLatin1Char('/') - + QStringLiteral("images") - + QLatin1Char('/'); + return QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QStringLiteral("images") + QLatin1Char('/'); } QString m_name; int m_identifier; - QList m_goals; - QHash m_activeGoal; + QList m_goals; + QHash m_activeGoal; }; } #endif // LEARNER_P_H diff --git a/liblearnerprofile/src/learninggoal.cpp b/liblearnerprofile/src/learninggoal.cpp index ebe4cc8..798c25d 100644 --- a/liblearnerprofile/src/learninggoal.cpp +++ b/liblearnerprofile/src/learninggoal.cpp @@ -1,94 +1,95 @@ /* * Copyright 2013 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "learninggoal.h" using namespace LearnerProfile; // private class LearningGoalPrivate -class LearningGoalPrivate { - +class LearningGoalPrivate +{ public: LearningGoalPrivate() : m_name(QString()) , m_identifier(QString()) , m_category(LearningGoal::Unspecified) { } - ~LearningGoalPrivate() {} + ~LearningGoalPrivate() + { + } QString m_name; QString m_identifier; LearningGoal::Category m_category; }; // methods of LearningGoal LearningGoal::LearningGoal(QObject *parent) : QObject(parent) , d(new LearningGoalPrivate) { // create goal of unspecified category } LearningGoal::LearningGoal(LearningGoal::Category category, const QString &identifier, QObject *parent) : QObject(parent) , d(new LearningGoalPrivate) { d->m_category = category; d->m_identifier = identifier; } QString LearningGoal::name() const { return d->m_name; } LearningGoal::~LearningGoal() { - } void LearningGoal::setName(const QString &name) { if (name == d->m_name) { return; } d->m_name = name; emit nameChanged(); } QString LearningGoal::identifier() const { return d->m_identifier; } void LearningGoal::setIdentifier(const QString &identifier) { if (identifier == d->m_identifier) { return; } d->m_identifier = identifier; emit identifierChanged(); } LearningGoal::Category LearningGoal::category() const { return d->m_category; } diff --git a/liblearnerprofile/src/learninggoal.h b/liblearnerprofile/src/learninggoal.h index d6255eb..c7d067a 100644 --- a/liblearnerprofile/src/learninggoal.h +++ b/liblearnerprofile/src/learninggoal.h @@ -1,71 +1,65 @@ /* * Copyright 2013 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef LEARNINGGOAL_H #define LEARNINGGOAL_H #include "liblearnerprofile_export.h" #include class LearningGoalPrivate; namespace LearnerProfile { - /** * \class LearningGoal */ class LIBLEARNERPROFILE_EXPORT LearningGoal : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString id READ identifier WRITE setIdentifier NOTIFY identifierChanged) Q_PROPERTY(Category category READ category) public: Q_ENUMS(Category) - enum Category { - Unspecified = 0, - Language = 1 - }; + enum Category { Unspecified = 0, Language = 1 }; explicit LearningGoal(QObject *parent = nullptr); - explicit LearningGoal(LearningGoal::Category category, - const QString &identifier, - QObject *parent = nullptr); + explicit LearningGoal(LearningGoal::Category category, const QString &identifier, QObject *parent = nullptr); ~LearningGoal(); QString name() const; void setName(const QString &name); QString identifier() const; void setIdentifier(const QString &identifier); LearningGoal::Category category() const; Q_SIGNALS: void nameChanged(); void identifierChanged(); private: Q_DISABLE_COPY(LearningGoal) const QScopedPointer d; }; } #endif // LEARNINGGOAL_H diff --git a/liblearnerprofile/src/models/learninggoalmodel.cpp b/liblearnerprofile/src/models/learninggoalmodel.cpp index f30c70d..14c99e8 100644 --- a/liblearnerprofile/src/models/learninggoalmodel.cpp +++ b/liblearnerprofile/src/models/learninggoalmodel.cpp @@ -1,243 +1,237 @@ /* * Copyright 2013-2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "learninggoalmodel.h" -#include "profilemanager.h" #include "learner.h" +#include "profilemanager.h" #include #include #include -#include #include "liblearner_debug.h" +#include using namespace LearnerProfile; // private class LearningGoalModelPrivate -class LearningGoalModelPrivate { +class LearningGoalModelPrivate +{ public: LearningGoalModelPrivate() : m_profileManager(nullptr) , m_learner(nullptr) , m_signalMapper(new QSignalMapper()) { } ~LearningGoalModelPrivate() { delete m_signalMapper; } void updateGoals(); void updateMappings(); ProfileManager *m_profileManager; Learner *m_learner; - QList m_goals; + QList m_goals; QSignalMapper *m_signalMapper; }; void LearningGoalModelPrivate::updateGoals() { m_goals.clear(); // set all registered goals from profile manager if (m_profileManager) { foreach (LearningGoal *goal, m_profileManager->goals()) { m_goals.append(goal); } } // TODO add learner status information } void LearningGoalModelPrivate::updateMappings() { if (!m_profileManager) { return; } int goals = m_goals.count(); for (int i = 0; i < goals; ++i) { m_signalMapper->setMapping(m_goals.at(i), i); } } // class LearningGoalModel LearningGoalModel::LearningGoalModel(QObject *parent) : QAbstractListModel(parent) , d(new LearningGoalModelPrivate) { - connect(d->m_signalMapper, static_cast(&QSignalMapper::mapped), - this, &LearningGoalModel::emitLearningGoalChanged); + connect(d->m_signalMapper, static_cast(&QSignalMapper::mapped), this, &LearningGoalModel::emitLearningGoalChanged); } LearningGoalModel::~LearningGoalModel() { - } -QHash< int, QByteArray > LearningGoalModel::roleNames() const +QHash LearningGoalModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; return roles; } void LearningGoalModel::setProfileManager(ProfileManager *profileManager) { if (d->m_profileManager == profileManager) { return; } beginResetModel(); if (d->m_profileManager) { d->m_profileManager->disconnect(this); } d->m_profileManager = profileManager; d->updateGoals(); d->updateMappings(); endResetModel(); emit profileManagerChanged(); } -ProfileManager * LearningGoalModel::profileManager() const +ProfileManager *LearningGoalModel::profileManager() const { return d->m_profileManager; } -Learner * LearningGoalModel::learner() const +Learner *LearningGoalModel::learner() const { return d->m_learner; } void LearningGoalModel::setLearner(Learner *learner) { if (!learner) { return; } beginResetModel(); if (d->m_learner) { learner->disconnect(this); } d->m_learner = learner; d->updateGoals(); d->updateMappings(); - connect(learner, &Learner::goalAboutToBeAdded, - this, &LearningGoalModel::onLearningGoalAboutToBeAdded); - connect(learner, &Learner::goalAdded, - this, &LearningGoalModel::onLearningGoalAdded); - connect(learner, &Learner::goalAboutToBeRemoved, this, - &LearningGoalModel::onLearningGoalAboutToBeRemoved); + connect(learner, &Learner::goalAboutToBeAdded, this, &LearningGoalModel::onLearningGoalAboutToBeAdded); + connect(learner, &Learner::goalAdded, this, &LearningGoalModel::onLearningGoalAdded); + connect(learner, &Learner::goalAboutToBeRemoved, this, &LearningGoalModel::onLearningGoalAboutToBeRemoved); emit learnerChanged(); endResetModel(); } QVariant LearningGoalModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() >= d->m_goals.count()) { return QVariant(); } - LearningGoal * const goal = d->m_goals.at(index.row()); - - switch(role) - { - case Qt::DisplayRole: - return !goal->name().isEmpty()? - QVariant(goal->name()): QVariant(i18nc("@item:inlistbox unknown learning goal", "unknown")); - case Qt::ToolTipRole: - return QVariant(goal->name()); - case TitleRole: - return goal->name(); - case IdRole: - return goal->identifier(); - case DataRole: - return QVariant::fromValue(goal); - default: - return QVariant(); + LearningGoal *const goal = d->m_goals.at(index.row()); + + switch (role) { + case Qt::DisplayRole: + return !goal->name().isEmpty() ? QVariant(goal->name()) : QVariant(i18nc("@item:inlistbox unknown learning goal", "unknown")); + case Qt::ToolTipRole: + return QVariant(goal->name()); + case TitleRole: + return goal->name(); + case IdRole: + return goal->identifier(); + case DataRole: + return QVariant::fromValue(goal); + default: + return QVariant(); } } int LearningGoalModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return d->m_goals.count(); } void LearningGoalModel::onLearningGoalAboutToBeAdded(LearningGoal *goal, int index) { Q_UNUSED(index) beginInsertRows(QModelIndex(), d->m_goals.count(), d->m_goals.count()); d->m_goals.append(goal); d->updateMappings(); } void LearningGoalModel::onLearningGoalAdded() { endInsertRows(); } void LearningGoalModel::onLearningGoalAboutToBeRemoved(int index) { if (!d->m_learner) { return; } if (index < 0 || d->m_goals.count() <= index) { qCWarning(LIBLEARNER_LOG) << "Cannot remove learning goal from model, not registered"; return; } beginRemoveRows(QModelIndex(), index, index); d->m_goals.removeAt(index); d->updateMappings(); endRemoveRows(); } void LearningGoalModel::emitLearningGoalChanged(int row) { emit learningGoalChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant LearningGoalModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Learning Goal")); } QVariant LearningGoalModel::learningGoal(int row) const { return data(index(row, 0), LearningGoalModel::DataRole); } diff --git a/liblearnerprofile/src/models/learninggoalmodel.h b/liblearnerprofile/src/models/learninggoalmodel.h index 27e3435..4d2ab76 100644 --- a/liblearnerprofile/src/models/learninggoalmodel.h +++ b/liblearnerprofile/src/models/learninggoalmodel.h @@ -1,80 +1,76 @@ /* * Copyright 2013-2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef LEARNINGGOALMODEL_H #define LEARNINGGOALMODEL_H #include "liblearnerprofile_export.h" #include #include class LearningGoalModelPrivate; namespace LearnerProfile { class ProfileManager; class LearningGoal; class Learner; class LIBLEARNERPROFILE_EXPORT LearningGoalModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(LearnerProfile::ProfileManager *profileManager READ profileManager WRITE setProfileManager NOTIFY profileManagerChanged) Q_PROPERTY(LearnerProfile::Learner *learner READ learner WRITE setLearner NOTIFY learnerChanged) public: - enum learningGoalRoles { - TitleRole = Qt::UserRole + 1, - IdRole, - DataRole - }; + enum learningGoalRoles { TitleRole = Qt::UserRole + 1, IdRole, DataRole }; explicit LearningGoalModel(QObject *parent = nullptr); virtual ~LearningGoalModel(); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setProfileManager(ProfileManager *profileManager); - ProfileManager * profileManager() const; + ProfileManager *profileManager() const; void setLearner(Learner *learner); - Learner * learner() const; + Learner *learner() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_INVOKABLE QVariant learningGoal(int index) const; Q_SIGNALS: void profileManagerChanged(); void learnerChanged(); void learningGoalChanged(int index); private Q_SLOTS: void onLearningGoalAboutToBeAdded(LearningGoal *goal, int index); void onLearningGoalAdded(); void onLearningGoalAboutToBeRemoved(int index); void emitLearningGoalChanged(int row); private: const QScopedPointer d; }; } #endif // LEARNINGGOALMODEL_H diff --git a/liblearnerprofile/src/profilemanager.cpp b/liblearnerprofile/src/profilemanager.cpp index b5775e1..a268726 100644 --- a/liblearnerprofile/src/profilemanager.cpp +++ b/liblearnerprofile/src/profilemanager.cpp @@ -1,311 +1,296 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "profilemanager.h" -#include "storage.h" #include "learner.h" +#include "storage.h" -#include -#include -#include #include "liblearner_debug.h" #include #include -#include #include +#include +#include +#include +#include using namespace LearnerProfile; -///BEGIN: ProfileManagerPrivate -namespace LearnerProfile { -class ProfileManagerPrivate { - +/// BEGIN: ProfileManagerPrivate +namespace LearnerProfile +{ +class ProfileManagerPrivate +{ public: ProfileManagerPrivate(); - ~ProfileManagerPrivate() {} + ~ProfileManagerPrivate() + { + } void sync(); - QList m_profiles; + QList m_profiles; Learner *m_activeProfile; - QList m_goals; + QList m_goals; std::unique_ptr m_config; Storage m_storage; }; } LearnerProfile::ProfileManagerPrivate::ProfileManagerPrivate() - : m_profiles(QList()) + : m_profiles(QList()) , m_activeProfile(nullptr) , m_config(new KConfig(QStringLiteral("learnerprofilerc"))) { // load all profiles from storage m_goals.append(m_storage.loadGoals()); m_profiles.append(m_storage.loadProfiles(m_goals)); // set last used profile KConfigGroup activeProfileGroup(m_config.get(), "ActiveProfile"); int lastProfileId = activeProfileGroup.readEntry("profileId", "0").toInt(); QList activeGoalsCategories = activeProfileGroup.readEntry("activeGoalsCategories", QList()); QList activeGoalsIdentifiers = activeProfileGroup.readEntry("activeGoalsIdentifiers", QList()); foreach (Learner *learner, m_profiles) { if (learner->identifier() == lastProfileId) { m_activeProfile = learner; // set active goals if (activeGoalsCategories.count() == activeGoalsIdentifiers.count()) { for (int i = 0; i < activeGoalsCategories.count(); ++i) { - m_activeProfile->setActiveGoal( - static_cast(activeGoalsCategories.at(i)), - activeGoalsIdentifiers.at(i)); + m_activeProfile->setActiveGoal(static_cast(activeGoalsCategories.at(i)), activeGoalsIdentifiers.at(i)); } } else { qCCritical(LIBLEARNER_LOG()) << "Inconsistent goal category / identifier pairs found: aborting."; } break; } } if (m_activeProfile == nullptr) { qCDebug(LIBLEARNER_LOG()) << "No last active profile found, falling back to first found profile"; if (m_profiles.size() > 0) { m_activeProfile = m_profiles.at(0); } } } void ProfileManagerPrivate::sync() { // sync last used profile data if (m_activeProfile) { KConfigGroup activeProfileGroup(m_config.get(), "ActiveProfile"); activeProfileGroup.writeEntry("profileId", m_activeProfile->identifier()); // compute activer learning goals by category QList goalCatogries; QList goalIdentifiers; // compute used goals foreach (LearningGoal *goal, m_activeProfile->goals()) { if (!goalCatogries.contains(static_cast(goal->category()))) { goalCatogries.append(static_cast(goal->category())); } } // compute active goals foreach (int category, goalCatogries) { goalIdentifiers.append(m_activeProfile->activeGoal(static_cast(category))->identifier()); } activeProfileGroup.writeEntry("activeGoalsCategories", goalCatogries); activeProfileGroup.writeEntry("activeGoalsIdentifiers", goalIdentifiers); - } - else { + } else { qCCritical(LIBLEARNER_LOG()) << "No active profile selected, aborting sync."; } m_config->sync(); - //TODO only sync changed learner + // TODO only sync changed learner foreach (Learner *learner, m_profiles) { m_storage.storeProfile(learner); } } -///END: ProfileManagerPrivate - +/// END: ProfileManagerPrivate ProfileManager::ProfileManager(QObject *parent) : QObject(parent) , d(new ProfileManagerPrivate) { - connect (this, &ProfileManager::profileAdded, this, &ProfileManager::profileCountChanged); - connect (this, &ProfileManager::profileRemoved, this, &ProfileManager::profileCountChanged); + connect(this, &ProfileManager::profileAdded, this, &ProfileManager::profileCountChanged); + connect(this, &ProfileManager::profileRemoved, this, &ProfileManager::profileCountChanged); foreach (Learner *learner, d->m_profiles) { connect(learner, &Learner::goalRemoved, this, &ProfileManager::removeLearningGoal); } } ProfileManager::~ProfileManager() { for (auto learner : d->m_profiles) { learner->deleteLater(); } for (auto goal : d->m_goals) { goal->deleteLater(); } } -QList< Learner* > ProfileManager::profiles() const +QList ProfileManager::profiles() const { return d->m_profiles; } int ProfileManager::profileCount() const { return profiles().length(); } void ProfileManager::openImageFileDialog() { - const QString imagePath = QFileDialog::getOpenFileName( - nullptr, - i18n("Open Image"), - QLatin1String(""), - i18n("Image Files (*.png *.jpg *.bmp)")); + const QString imagePath = QFileDialog::getOpenFileName(nullptr, i18n("Open Image"), QLatin1String(""), i18n("Image Files (*.png *.jpg *.bmp)")); d->m_activeProfile->importImage(imagePath); } -Learner * ProfileManager::addProfile(const QString &name) +Learner *ProfileManager::addProfile(const QString &name) { Learner *learner = new Learner(this); learner->setName(name); // set id int maxUsedId = 0; foreach (Learner *cpLearner, d->m_profiles) { if (cpLearner->identifier() >= maxUsedId) { maxUsedId = cpLearner->identifier(); } } learner->setIdentifier(maxUsedId + 1); d->m_profiles.append(learner); d->m_storage.storeProfile(learner); emit profileAdded(learner, d->m_profiles.count() - 1); if (activeProfile() == nullptr) { setActiveProfile(learner); } - connect (learner, SIGNAL(goalRemoved(Learner*,LearningGoal*)), - this, SLOT(removeLearningGoal(Learner*,LearningGoal*))); + connect(learner, SIGNAL(goalRemoved(Learner *, LearningGoal *)), this, SLOT(removeLearningGoal(Learner *, LearningGoal *))); return learner; } void ProfileManager::removeProfile(Learner *learner) { int index = d->m_profiles.indexOf(learner); if (index < 0) { qCWarning(LIBLEARNER_LOG()) << "Profile was not found, aborting"; return; } emit profileAboutToBeRemoved(index); d->m_profiles.removeAt(index); d->m_storage.removeProfile(learner); if (d->m_activeProfile == learner) { if (d->m_profiles.isEmpty()) { setActiveProfile(nullptr); - } - else { + } else { setActiveProfile(d->m_profiles.at(0)); } } emit profileRemoved(); } -void ProfileManager::removeLearningGoal(Learner* learner, LearningGoal* goal) +void ProfileManager::removeLearningGoal(Learner *learner, LearningGoal *goal) { d->m_storage.removeRelation(learner, goal); } -Learner * ProfileManager::profile(int index) +Learner *ProfileManager::profile(int index) { if (index < 0 || index >= profiles().count()) { return nullptr; } return profiles().at(index); } -QList< LearningGoal* > ProfileManager::goals() const +QList ProfileManager::goals() const { return d->m_goals; } -LearningGoal * ProfileManager::registerGoal(LearningGoal::Category category, - const QString &identifier, - const QString &name) +LearningGoal *ProfileManager::registerGoal(LearningGoal::Category category, const QString &identifier, const QString &name) { // test whether goal is already registered foreach (LearningGoal *cmpGoal, d->m_goals) { if (cmpGoal->category() == category && cmpGoal->identifier() == identifier) { return cmpGoal; } } LearningGoal *goal = new LearningGoal(category, identifier, this); goal->setName(name); d->m_goals.append(goal); d->m_storage.storeGoal(goal); return goal; } -LearnerProfile::LearningGoal * LearnerProfile::ProfileManager::goal( - LearningGoal::Category category, - const QString& identifier) const +LearnerProfile::LearningGoal *LearnerProfile::ProfileManager::goal(LearningGoal::Category category, const QString &identifier) const { foreach (LearningGoal *goal, d->m_goals) { if (goal->category() == category && goal->identifier() == identifier) { return goal; } } return nullptr; } -void ProfileManager::recordProgress(Learner *learner, - LearningGoal *goal, - const QString &container, const QString &item, - int logPayload, int valuePayload) +void ProfileManager::recordProgress(Learner *learner, LearningGoal *goal, const QString &container, const QString &item, int logPayload, int valuePayload) { if (!learner) { qCDebug(LIBLEARNER_LOG()) << "No learner set, no data stored"; return; } d->m_storage.storeProgressLog(learner, goal, container, item, logPayload, QDateTime::currentDateTime()); d->m_storage.storeProgressValue(learner, goal, container, item, valuePayload); } -QHash ProfileManager::progressValues(Learner *learner, LearningGoal *goal, - const QString &container) const +QHash ProfileManager::progressValues(Learner *learner, LearningGoal *goal, const QString &container) const { if (!learner || !goal) { return QHash(); } return d->m_storage.readProgressValues(learner, goal, container); } void ProfileManager::sync() { d->sync(); } void ProfileManager::sync(Learner *learner) { d->m_storage.storeProfile(learner); } -Learner * ProfileManager::activeProfile() const +Learner *ProfileManager::activeProfile() const { return d->m_activeProfile; } -void ProfileManager::setActiveProfile(Learner* learner) +void ProfileManager::setActiveProfile(Learner *learner) { if (learner == d->m_activeProfile) { return; } d->m_activeProfile = learner; emit activeProfileChanged(); } diff --git a/liblearnerprofile/src/profilemanager.h b/liblearnerprofile/src/profilemanager.h index a842c85..7a3e18a 100644 --- a/liblearnerprofile/src/profilemanager.h +++ b/liblearnerprofile/src/profilemanager.h @@ -1,104 +1,98 @@ /* * Copyright 2013 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef PROFILEMANAGER_H #define PROFILEMANAGER_H -#include "liblearnerprofile_export.h" #include "learninggoal.h" +#include "liblearnerprofile_export.h" #include namespace LearnerProfile { class ProfileManagerPrivate; class Learner; class LearningGoal; /** * \class ProfileManager */ class LIBLEARNERPROFILE_EXPORT ProfileManager : public QObject { Q_OBJECT - Q_PROPERTY (int profileCount READ profileCount NOTIFY profileCountChanged) - Q_PROPERTY (LearnerProfile::Learner * activeProfile READ activeProfile WRITE setActiveProfile NOTIFY activeProfileChanged) + Q_PROPERTY(int profileCount READ profileCount NOTIFY profileCountChanged) + Q_PROPERTY(LearnerProfile::Learner *activeProfile READ activeProfile WRITE setActiveProfile NOTIFY activeProfileChanged) public: - enum Progress { - Skip = 0, - Next = 1 - }; + enum Progress { Skip = 0, Next = 1 }; explicit ProfileManager(QObject *parent = nullptr); virtual ~ProfileManager(); - QList< Learner* > profiles() const; + QList profiles() const; int profileCount() const; - Q_INVOKABLE LearnerProfile::Learner * addProfile(const QString &name); + Q_INVOKABLE LearnerProfile::Learner *addProfile(const QString &name); Q_INVOKABLE void removeProfile(LearnerProfile::Learner *learner); - Q_INVOKABLE LearnerProfile::Learner * profile(int index); + Q_INVOKABLE LearnerProfile::Learner *profile(int index); Q_INVOKABLE void openImageFileDialog(); - QList< LearningGoal* > goals() const; + QList goals() const; /** * Register learning goal if not registered yet. The registered goals will be stored at the * internal database. */ - LearningGoal * registerGoal(LearningGoal::Category category, const QString &identifier, const QString &name); - LearningGoal * goal(LearningGoal::Category category, const QString &identifier) const; + LearningGoal *registerGoal(LearningGoal::Category category, const QString &identifier, const QString &name); + LearningGoal *goal(LearningGoal::Category category, const QString &identifier) const; /** * updates current learning goal by activity, adds new learning goal if necessary, * stores log data for this activity */ - void recordProgress(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item, - int logPayload, int valuePayload); + void recordProgress(Learner *learner, LearningGoal *goal, const QString &container, const QString &item, int logPayload, int valuePayload); /** * \return progress value, or -1 if value is not available yet */ - QHash progressValues(Learner *learner, LearningGoal *goal, - const QString &container) const; + QHash progressValues(Learner *learner, LearningGoal *goal, const QString &container) const; /** * write all profiles to database */ Q_INVOKABLE void sync(); /** * write specified \p profile to database */ Q_INVOKABLE void sync(LearnerProfile::Learner *learner); void setActiveProfile(LearnerProfile::Learner *learner); - LearnerProfile::Learner * activeProfile() const; + LearnerProfile::Learner *activeProfile() const; Q_SIGNALS: void activeProfileChanged(); - void profileAdded(Learner*,int); + void profileAdded(Learner *, int); void profileAboutToBeRemoved(int); void profileRemoved(); void profileCountChanged(); private Q_SLOTS: void removeLearningGoal(Learner *learner, LearningGoal *goal); private: Q_DISABLE_COPY(ProfileManager) const QScopedPointer d; }; } #endif // PROFILEMANAGER_H diff --git a/liblearnerprofile/src/storage.cpp b/liblearnerprofile/src/storage.cpp index 2170ebc..546ded3 100644 --- a/liblearnerprofile/src/storage.cpp +++ b/liblearnerprofile/src/storage.cpp @@ -1,679 +1,680 @@ /* * Copyright 2013-2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "storage.h" #include "learner.h" #include "liblearner_debug.h" #include #include #include -#include #include +#include #include #include using namespace LearnerProfile; -Storage::Storage(QObject* parent) +Storage::Storage(QObject *parent) : QObject(parent) - , m_databasePath(QStandardPaths::writableLocation( - QStandardPaths::DataLocation) + QLatin1Char('/') + "learnerdata.db") + , m_databasePath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "learnerdata.db") , m_errorMessage(QString()) { - } -Storage::Storage(const QString &databasePath, QObject* parent) +Storage::Storage(const QString &databasePath, QObject *parent) : QObject(parent) , m_databasePath(databasePath) , m_errorMessage(QString()) { qCDebug(LIBLEARNER_LOG) << "Initialize with custom DB path:" << m_databasePath; } QString Storage::errorMessage() const { return m_errorMessage; } void Storage::raiseError(const QSqlError &error) { m_errorMessage = QStringLiteral("%1 : %2").arg(error.driverText(), error.databaseText()); emit errorMessageChanged(); } bool Storage::storeProfile(Learner *learner) { QSqlDatabase db = database(); // test whether ID is present QSqlQuery idExistsQuery(db); idExistsQuery.prepare(QStringLiteral("SELECT COUNT(*) FROM profiles WHERE id = :id")); idExistsQuery.bindValue(QStringLiteral(":id"), learner->identifier()); idExistsQuery.exec(); if (db.lastError().isValid()) { qCritical() << "ExistsQuery: " << db.lastError().text(); raiseError(db.lastError()); return false; } // go to first result row that contains the count idExistsQuery.next(); if (idExistsQuery.value(0).toInt() < 1) { // in case learner ID is not found in database QSqlQuery insertProfileQuery(db); insertProfileQuery.prepare(QStringLiteral("INSERT INTO profiles (id, name) VALUES (?, ?)")); insertProfileQuery.bindValue(0, learner->identifier()); insertProfileQuery.bindValue(1, learner->name()); insertProfileQuery.exec(); if (insertProfileQuery.lastError().isValid()) { raiseError(insertProfileQuery.lastError()); db.rollback(); return false; } } else { // update name otherwise QSqlQuery updateProfileQuery(db); updateProfileQuery.prepare(QStringLiteral("UPDATE profiles SET name = :name WHERE id = :id")); updateProfileQuery.bindValue(QStringLiteral(":id"), learner->identifier()); updateProfileQuery.bindValue(QStringLiteral(":name"), learner->name()); updateProfileQuery.exec(); if (updateProfileQuery.lastError().isValid()) { qCritical() << updateProfileQuery.lastError().text(); raiseError(updateProfileQuery.lastError()); db.rollback(); return false; } } // store existing learning goal relations foreach (LearningGoal *goal, learner->goals()) { QSqlQuery relationExistsQuery(db); - relationExistsQuery.prepare("SELECT COUNT(*) FROM learner_goals " + relationExistsQuery.prepare( + "SELECT COUNT(*) FROM learner_goals " "WHERE goal_category = :goalCategory " "AND goal_identifier = :goalIdentifier " - "AND profile_id = :profileId " - ); + "AND profile_id = :profileId "); relationExistsQuery.bindValue(QStringLiteral(":goalCategory"), goal->category()); relationExistsQuery.bindValue(QStringLiteral(":goalIdentifier"), goal->identifier()); relationExistsQuery.bindValue(QStringLiteral(":profileId"), learner->identifier()); relationExistsQuery.exec(); if (db.lastError().isValid()) { qCritical() << "ExistsQuery: " << db.lastError().text(); raiseError(db.lastError()); return false; } // go to first result row that contains the count relationExistsQuery.next(); if (relationExistsQuery.value(0).toInt() < 1) { QSqlQuery insertProfileQuery(db); insertProfileQuery.prepare(QStringLiteral("INSERT INTO learner_goals (goal_category, goal_identifier, profile_id) VALUES (?, ?, ?)")); insertProfileQuery.bindValue(0, goal->category()); insertProfileQuery.bindValue(1, goal->identifier()); insertProfileQuery.bindValue(2, learner->identifier()); insertProfileQuery.exec(); } } // remove deleted relations QSqlQuery cleanupRelations(db); cleanupRelations.prepare(QStringLiteral("DELETE FROM learner_goals WHERE ")); - //TODO change creation of relations to same way as remove-relations: explicit connections + // TODO change creation of relations to same way as remove-relations: explicit connections return true; } bool Storage::removeProfile(Learner *learner) { QSqlDatabase db = database(); QSqlQuery removeProfileQuery(db); // delete learner removeProfileQuery.prepare(QStringLiteral("DELETE FROM profiles WHERE id = ?")); removeProfileQuery.bindValue(0, learner->identifier()); removeProfileQuery.exec(); if (removeProfileQuery.lastError().isValid()) { qCritical() << removeProfileQuery.lastError().text(); raiseError(removeProfileQuery.lastError()); db.rollback(); return false; } // delete learning goal relations QSqlQuery removeGoalRelationQuery(db); removeGoalRelationQuery.prepare(QStringLiteral("DELETE FROM learner_goals WHERE profile_id = ?")); removeGoalRelationQuery.bindValue(0, learner->identifier()); removeGoalRelationQuery.exec(); if (removeGoalRelationQuery.lastError().isValid()) { qCritical() << removeGoalRelationQuery.lastError().text(); raiseError(removeGoalRelationQuery.lastError()); db.rollback(); return false; } return true; } bool Storage::removeRelation(Learner *learner, LearningGoal *goal) { QSqlDatabase db = database(); QSqlQuery removeGoalRelationQuery(db); removeGoalRelationQuery.prepare( "DELETE FROM learner_goals " "WHERE goal_category = :goalCategory " "AND goal_identifier = :goalIdentifier " - "AND profile_id = :profileId " - ); + "AND profile_id = :profileId "); removeGoalRelationQuery.bindValue(QStringLiteral(":goalCategory"), goal->category()); removeGoalRelationQuery.bindValue(QStringLiteral(":goalIdentifier"), goal->identifier()); removeGoalRelationQuery.bindValue(QStringLiteral(":profileId"), learner->identifier()); removeGoalRelationQuery.exec(); if (db.lastError().isValid()) { qCritical() << "ExistsQuery: " << db.lastError().text(); raiseError(db.lastError()); return false; } return true; } -QList< Learner* > Storage::loadProfiles(QList goals) +QList Storage::loadProfiles(QList goals) { QSqlDatabase db = database(); QSqlQuery profileQuery(db); profileQuery.prepare(QStringLiteral("SELECT id, name FROM profiles")); profileQuery.exec(); if (profileQuery.lastError().isValid()) { qCritical() << profileQuery.lastError().text(); raiseError(profileQuery.lastError()); - return QList(); + return QList(); } - QList profiles; + QList profiles; while (profileQuery.next()) { - Learner* profile = new Learner(); + Learner *profile = new Learner(); profile->setIdentifier(profileQuery.value(0).toInt()); profile->setName(profileQuery.value(1).toString()); profiles.append(profile); } // associate to goals QSqlQuery goalRelationQuery(db); goalRelationQuery.prepare(QStringLiteral("SELECT goal_category, goal_identifier, profile_id FROM learner_goals")); goalRelationQuery.exec(); if (goalRelationQuery.lastError().isValid()) { qCritical() << goalRelationQuery.lastError().text(); raiseError(goalRelationQuery.lastError()); - return QList(); + return QList(); } while (goalRelationQuery.next()) { Learner *learner = nullptr; LearningGoal *goal = nullptr; foreach (Learner *cmpProfile, profiles) { if (cmpProfile->identifier() == goalRelationQuery.value(2).toInt()) { learner = cmpProfile; break; } } if (!learner) { qCCritical(LIBLEARNER_LOG) << "Could not retrieve learner from database."; - return QList(); + return QList(); } foreach (LearningGoal *cmpGoal, goals) { - if (cmpGoal->category() == goalRelationQuery.value(0).toInt() - && cmpGoal->identifier() == goalRelationQuery.value(1).toString()) - { + if (cmpGoal->category() == goalRelationQuery.value(0).toInt() && cmpGoal->identifier() == goalRelationQuery.value(1).toString()) { goal = cmpGoal; break; } } if (learner->goals().contains(goal)) { continue; } if (goal) { learner->addGoal(goal); } } return profiles; } bool Storage::storeGoal(LearningGoal *goal) { QSqlDatabase db = database(); // test whether ID is present QSqlQuery goalExistsQuery(db); goalExistsQuery.prepare(QStringLiteral("SELECT COUNT(*) FROM goals WHERE category = :category AND identifier = :identifier")); goalExistsQuery.bindValue(QStringLiteral(":identifier"), goal->identifier()); goalExistsQuery.bindValue(QStringLiteral(":category"), static_cast(goal->category())); goalExistsQuery.exec(); if (db.lastError().isValid()) { qCritical() << "ExistsQuery: " << db.lastError().text(); raiseError(db.lastError()); return false; } // go to first result row that contains the count goalExistsQuery.next(); if (goalExistsQuery.value(0).toInt() < 1) { // in case learner ID is not found in database QSqlQuery insertGoalQuery(db); insertGoalQuery.prepare(QStringLiteral("INSERT INTO goals (category, identifier, name) VALUES (?, ?, ?)")); insertGoalQuery.bindValue(0, static_cast(goal->category())); insertGoalQuery.bindValue(1, goal->identifier()); insertGoalQuery.bindValue(2, goal->name()); insertGoalQuery.exec(); if (insertGoalQuery.lastError().isValid()) { raiseError(insertGoalQuery.lastError()); db.rollback(); return false; } return true; } else { // update name otherwise QSqlQuery updateGoalQuery(db); updateGoalQuery.prepare(QStringLiteral("UPDATE goals SET name = :name WHERE category = :category AND identifier = :identifier")); updateGoalQuery.bindValue(QStringLiteral(":category"), static_cast(goal->category())); updateGoalQuery.bindValue(QStringLiteral(":identifier"), goal->identifier()); updateGoalQuery.bindValue(QStringLiteral(":name"), goal->name()); updateGoalQuery.exec(); if (updateGoalQuery.lastError().isValid()) { qCritical() << updateGoalQuery.lastError().text(); raiseError(updateGoalQuery.lastError()); db.rollback(); return false; } return true; } } -QList< LearningGoal* > Storage::loadGoals() +QList Storage::loadGoals() { QSqlDatabase db = database(); QSqlQuery goalQuery(db); goalQuery.prepare(QStringLiteral("SELECT category, identifier, name FROM goals")); goalQuery.exec(); if (goalQuery.lastError().isValid()) { qCritical() << goalQuery.lastError().text(); raiseError(goalQuery.lastError()); - return QList(); + return QList(); } - QList goals; + QList goals; while (goalQuery.next()) { LearningGoal::Category category = static_cast(goalQuery.value(0).toInt()); QString identifier = goalQuery.value(1).toString(); QString name = goalQuery.value(2).toString(); - LearningGoal* goal = new LearningGoal(category, identifier); + LearningGoal *goal = new LearningGoal(category, identifier); goal->setName(name); goals.append(goal); } return goals; } -bool Storage::storeProgressLog(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item, int payload, - const QDateTime &time) +bool Storage::storeProgressLog(Learner *learner, LearningGoal *goal, const QString &container, const QString &item, int payload, const QDateTime &time) { QSqlDatabase db = database(); QSqlQuery insertQuery(db); - insertQuery.prepare("INSERT INTO learner_progress_log " + insertQuery.prepare( + "INSERT INTO learner_progress_log " "(goal_category, goal_identifier, profile_id, item_container, item, payload, date) " "VALUES (:gcategory, :gidentifier, :pid, :container, :item, :payload, :date)"); insertQuery.bindValue(QStringLiteral(":gcategory"), static_cast(goal->category())); insertQuery.bindValue(QStringLiteral(":gidentifier"), goal->identifier()); insertQuery.bindValue(QStringLiteral(":pid"), learner->identifier()); insertQuery.bindValue(QStringLiteral(":container"), container); insertQuery.bindValue(QStringLiteral(":item"), item); insertQuery.bindValue(QStringLiteral(":payload"), payload); insertQuery.bindValue(QStringLiteral(":date"), time.toString(Qt::ISODate)); insertQuery.exec(); if (insertQuery.lastError().isValid()) { raiseError(insertQuery.lastError()); qCCritical(LIBLEARNER_LOG) << "DB Error:" << m_errorMessage; db.rollback(); return false; } return true; } -QList> Storage::readProgressLog(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item) +QList> Storage::readProgressLog(Learner *learner, LearningGoal *goal, const QString &container, const QString &item) { QSqlDatabase db = database(); QSqlQuery logQuery(db); - logQuery.prepare("SELECT date, payload FROM learner_progress_log " + logQuery.prepare( + "SELECT date, payload FROM learner_progress_log " "WHERE goal_category = :goalcategory " "AND goal_identifier = :goalid " "AND profile_id = :profileid " "AND item_container = :container " "AND item = :item"); logQuery.bindValue(QStringLiteral(":goalcategory"), static_cast(goal->category())); logQuery.bindValue(QStringLiteral(":goalid"), goal->identifier()); logQuery.bindValue(QStringLiteral(":profileid"), learner->identifier()); logQuery.bindValue(QStringLiteral(":container"), container); logQuery.bindValue(QStringLiteral(":item"), item); logQuery.exec(); if (logQuery.lastError().isValid()) { qCritical() << logQuery.lastError().text(); raiseError(logQuery.lastError()); - return QList>(); + return QList>(); } - QList> log; + QList> log; while (logQuery.next()) { - const QDateTime date{logQuery.value(0).toDateTime()}; - int payload{logQuery.value(1).toInt()}; + const QDateTime date {logQuery.value(0).toDateTime()}; + int payload {logQuery.value(1).toInt()}; log.append(qMakePair(date, payload)); } return log; } -bool Storage::storeProgressValue(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item, int payload) +bool Storage::storeProgressValue(Learner *learner, LearningGoal *goal, const QString &container, const QString &item, int payload) { QSqlDatabase db = database(); QSqlQuery query(db); // test if already payload stored - query.prepare("SELECT payload FROM learner_progress_value " + query.prepare( + "SELECT payload FROM learner_progress_value " "WHERE goal_category = :gcategory " "AND goal_identifier = :gidentifier " "AND profile_id = :pid " "AND item_container = :container " "AND item = :item"); query.bindValue(QStringLiteral(":gcategory"), static_cast(goal->category())); query.bindValue(QStringLiteral(":gidentifier"), goal->identifier()); query.bindValue(QStringLiteral(":pid"), learner->identifier()); query.bindValue(QStringLiteral(":container"), container); query.bindValue(QStringLiteral(":item"), item); query.exec(); if (query.lastError().isValid()) { qCritical() << query.lastError().text(); raiseError(query.lastError()); return false; } // if query contains values, perform update query if (query.next()) { query.finish(); // release resources from previous query - query.prepare("UPDATE learner_progress_value " + query.prepare( + "UPDATE learner_progress_value " "SET payload = :payload " "WHERE goal_category = :gcategory " "AND goal_identifier = :gidentifier " "AND profile_id = :pid " "AND item_container = :container " "AND item = :item"); query.bindValue(QStringLiteral(":payload"), static_cast(payload)); query.bindValue(QStringLiteral(":gcategory"), static_cast(goal->category())); query.bindValue(QStringLiteral(":gidentifier"), goal->identifier()); query.bindValue(QStringLiteral(":pid"), learner->identifier()); query.bindValue(QStringLiteral(":container"), container); query.bindValue(QStringLiteral(":item"), item); query.exec(); if (query.lastError().isValid()) { qCritical() << query.lastError().text(); raiseError(query.lastError()); db.rollback(); return false; } return true; } // else insert new row else { query.finish(); // release resources from previous query - query.prepare("INSERT INTO learner_progress_value " + query.prepare( + "INSERT INTO learner_progress_value " "(goal_category, goal_identifier, profile_id, item_container, item, payload) " "VALUES (:gcategory, :gidentifier, :pid, :container, :item, :payload)"); query.bindValue(QStringLiteral(":gcategory"), static_cast(goal->category())); query.bindValue(QStringLiteral(":gidentifier"), goal->identifier()); query.bindValue(QStringLiteral(":pid"), learner->identifier()); query.bindValue(QStringLiteral(":container"), container); query.bindValue(QStringLiteral(":item"), item); query.bindValue(QStringLiteral(":payload"), static_cast(payload)); query.exec(); if (query.lastError().isValid()) { qCritical() << query.lastError().text(); raiseError(query.lastError()); db.rollback(); return false; } return true; } Q_UNREACHABLE(); return false; } -QHash Storage::readProgressValues(Learner *learner, LearningGoal *goal, - const QString &container) +QHash Storage::readProgressValues(Learner *learner, LearningGoal *goal, const QString &container) { QSqlDatabase db = database(); QSqlQuery query(db); - query.prepare("SELECT item, payload FROM learner_progress_value " + query.prepare( + "SELECT item, payload FROM learner_progress_value " "WHERE goal_category = :goalcategory " "AND goal_identifier = :goalid " "AND profile_id = :profileid " "AND item_container = :container"); query.bindValue(QStringLiteral(":goalcategory"), static_cast(goal->category())); query.bindValue(QStringLiteral(":goalid"), goal->identifier()); query.bindValue(QStringLiteral(":profileid"), learner->identifier()); query.bindValue(QStringLiteral(":container"), container); query.exec(); if (query.lastError().isValid()) { qCritical() << query.lastError().text(); raiseError(query.lastError()); - return QHash(); + return QHash(); } - QHash values; + QHash values; while (query.next()) { - const QString item{query.value(0).toString()}; - const int payload{query.value(1).toInt()}; + const QString item {query.value(0).toString()}; + const int payload {query.value(1).toInt()}; values.insert(item, payload); } return values; } -int Storage::readProgressValue(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item) +int Storage::readProgressValue(Learner *learner, LearningGoal *goal, const QString &container, const QString &item) { QSqlDatabase db = database(); QSqlQuery query(db); - query.prepare("SELECT payload FROM learner_progress_value " + query.prepare( + "SELECT payload FROM learner_progress_value " "WHERE goal_category = :goalcategory " "AND goal_identifier = :goalid " "AND profile_id = :profileid " "AND item_container = :container " "AND item = :item"); query.bindValue(QStringLiteral(":goalcategory"), static_cast(goal->category())); query.bindValue(QStringLiteral(":goalid"), goal->identifier()); query.bindValue(QStringLiteral(":profileid"), learner->identifier()); query.bindValue(QStringLiteral(":container"), container); query.bindValue(QStringLiteral(":item"), item); query.exec(); if (query.lastError().isValid()) { qCritical() << query.lastError().text(); raiseError(query.lastError()); return -1; } if (query.next()) { return query.value(0).toInt(); } return -1; } QSqlDatabase Storage::database() { if (QSqlDatabase::contains(QSqlDatabase::defaultConnection)) { return QSqlDatabase::database(QSqlDatabase::defaultConnection); } // create data directory if it does not exist QDir dir = QDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); if (!dir.exists()) { dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); } qCDebug(LIBLEARNER_LOG) << "Database path: " << m_databasePath; QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE")); db.setDatabaseName(m_databasePath); if (!db.open()) { qCritical() << "Could not open database: " << db.lastError().text(); raiseError(db.lastError()); return db; } if (!updateSchema()) { qCritical() << "Database scheme not correct."; return db; } // return correctly set up database return db; } bool Storage::updateSchema() { QSqlDatabase db = database(); // check database version format - db.exec("CREATE TABLE IF NOT EXISTS metadata (" - "key TEXT PRIMARY KEY, " - "value TEXT" - ")"); + db.exec( + "CREATE TABLE IF NOT EXISTS metadata (" + "key TEXT PRIMARY KEY, " + "value TEXT" + ")"); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } QSqlQuery versionQuery = db.exec(QStringLiteral("SELECT value FROM metadata WHERE key = 'version'")); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } if (versionQuery.next()) { QString version = versionQuery.value(0).toString(); if (version != QLatin1String("1")) { m_errorMessage = i18n("Invalid database version '%1'.", version); emit errorMessageChanged(); return false; } - } - else { + } else { if (!db.transaction()) { - qCWarning(LIBLEARNER_LOG) << db.lastError().text(); + qCWarning(LIBLEARNER_LOG) << db.lastError().text(); raiseError(db.lastError()); return false; } db.exec(QStringLiteral("INSERT INTO metadata (key, value) VALUES ('version', '1')")); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } if (!db.commit()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } } // table for learner profiles - db.exec("CREATE TABLE IF NOT EXISTS profiles (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "name TEXT" - ")"); + db.exec( + "CREATE TABLE IF NOT EXISTS profiles (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT" + ")"); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } // table for registered learning goals - db.exec("CREATE TABLE IF NOT EXISTS goals (" - "category INTEGER, " // LearningGoal::Category - "identifier TEXT, " // identifier, unique per Category - "name TEXT, " // name - "PRIMARY KEY ( category, identifier )" - ")"); + db.exec( + "CREATE TABLE IF NOT EXISTS goals (" + "category INTEGER, " // LearningGoal::Category + "identifier TEXT, " // identifier, unique per Category + "name TEXT, " // name + "PRIMARY KEY ( category, identifier )" + ")"); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } // table for learner - learningGoal relations - db.exec("CREATE TABLE IF NOT EXISTS learner_goals (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "goal_category INTEGER, " // LearningGoal::Category - "goal_identifier TEXT, " // LearningGoal::Identifier - "profile_id INTEGER " // Learner::Identifier - ")"); + db.exec( + "CREATE TABLE IF NOT EXISTS learner_goals (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "goal_category INTEGER, " // LearningGoal::Category + "goal_identifier TEXT, " // LearningGoal::Identifier + "profile_id INTEGER " // Learner::Identifier + ")"); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } // table for full progress data log - db.exec("CREATE TABLE IF NOT EXISTS learner_progress_log (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "goal_category INTEGER, " // LearningGoal::Category - "goal_identifier TEXT, " // LearningGoal::Identifier - "profile_id INTEGER, " // Learner::Identifier - "item_container TEXT, " - "item TEXT, " - "payload INTEGER, " - "date TEXT" - ")"); + db.exec( + "CREATE TABLE IF NOT EXISTS learner_progress_log (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "goal_category INTEGER, " // LearningGoal::Category + "goal_identifier TEXT, " // LearningGoal::Identifier + "profile_id INTEGER, " // Learner::Identifier + "item_container TEXT, " + "item TEXT, " + "payload INTEGER, " + "date TEXT" + ")"); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } // table for progress data quick access - db.exec("CREATE TABLE IF NOT EXISTS learner_progress_value (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "goal_category INTEGER, " // LearningGoal::Category - "goal_identifier TEXT, " // LearningGoal::Identifier - "profile_id INTEGER, " // Learner::Identifier - "item_container TEXT, " - "item TEXT, " - "payload INTEGER" - ")"); + db.exec( + "CREATE TABLE IF NOT EXISTS learner_progress_value (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "goal_category INTEGER, " // LearningGoal::Category + "goal_identifier TEXT, " // LearningGoal::Identifier + "profile_id INTEGER, " // Learner::Identifier + "item_container TEXT, " + "item TEXT, " + "payload INTEGER" + ")"); if (db.lastError().isValid()) { qCritical() << db.lastError().text(); raiseError(db.lastError()); return false; } return true; } diff --git a/liblearnerprofile/src/storage.h b/liblearnerprofile/src/storage.h index 67af00a..966590b 100644 --- a/liblearnerprofile/src/storage.h +++ b/liblearnerprofile/src/storage.h @@ -1,103 +1,96 @@ /* * Copyright 2013-2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef STORAGE_H #define STORAGE_H #include class QSqlError; class QSqlDatabase; namespace LearnerProfile { - class Learner; class LearningGoal; /** * \class Storage * Database storage for learner information database. */ class Storage : public QObject { Q_OBJECT Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) public: /** * Default constructor, which sets a default database path at * DataLocation + learnerdata.db */ - explicit Storage(QObject* parent = nullptr); + explicit Storage(QObject *parent = nullptr); /** * \note this constructor is tailored for unit tests */ - explicit Storage(const QString &databasePath, QObject* parent = nullptr); + explicit Storage(const QString &databasePath, QObject *parent = nullptr); QString errorMessage() const; /** * Store profile in database. This can either be a new or an existing profile. * If it is an existing profile, the corresponding values are updated. */ bool storeProfile(Learner *learner); bool removeProfile(Learner *learner); bool removeRelation(Learner *learner, LearningGoal *goal); - QList loadProfiles(QList< LearnerProfile::LearningGoal* > goals); + QList loadProfiles(QList goals); bool storeGoal(LearningGoal *goal); QList loadGoals(); - bool storeProgressLog(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item, int payload, - const QDateTime &time); + bool storeProgressLog(Learner *learner, LearningGoal *goal, const QString &container, const QString &item, int payload, const QDateTime &time); /** * Load list of progress values for specified item * \return list of date/payload values for this item */ - QList> readProgressLog(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item); - bool storeProgressValue(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item, int payload); + QList> readProgressLog(Learner *learner, LearningGoal *goal, const QString &container, const QString &item); + bool storeProgressValue(Learner *learner, LearningGoal *goal, const QString &container, const QString &item, int payload); /** * Load list of progress values for specified container * \return list of item/payload values for all items in container */ - QHash readProgressValues(Learner *learner, LearningGoal *goal, - const QString &container); + QHash readProgressValues(Learner *learner, LearningGoal *goal, const QString &container); /** * Load payload value of specified item. If no value is found, \return -1 */ - int readProgressValue(Learner *learner, LearningGoal *goal, - const QString &container, const QString &item); + int readProgressValue(Learner *learner, LearningGoal *goal, const QString &container, const QString &item); Q_SIGNALS: void errorMessageChanged(); protected: QSqlDatabase database(); void raiseError(const QSqlError &error); private: bool updateSchema(); const QString m_databasePath; QString m_errorMessage; }; } #endif // STORAGE_H diff --git a/libsound/src/backendinterface.cpp b/libsound/src/backendinterface.cpp index f89ea98..a143843 100644 --- a/libsound/src/backendinterface.cpp +++ b/libsound/src/backendinterface.cpp @@ -1,35 +1,33 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "backendinterface.h" BackendInterface::BackendInterface(const QString &name, QObject *parent) : QObject(parent) , m_name(name) { - } BackendInterface::~BackendInterface() { - } QString BackendInterface::name() const { return m_name; } diff --git a/libsound/src/backendinterface.h b/libsound/src/backendinterface.h index 501e6de..57f6a30 100644 --- a/libsound/src/backendinterface.h +++ b/libsound/src/backendinterface.h @@ -1,44 +1,44 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef BACKENDINTERFACE_H #define BACKENDINTERFACE_H #include "libsound_export.h" #include #include class CaptureBackendInterface; class OutputBackendInterface; class LIBSOUND_EXPORT BackendInterface : public QObject { Q_OBJECT public: explicit BackendInterface(const QString &name, QObject *parent = nullptr); virtual ~BackendInterface(); QString name() const; - virtual CaptureBackendInterface * captureBackend() const = 0; - virtual OutputBackendInterface * outputBackend() const = 0; + virtual CaptureBackendInterface *captureBackend() const = 0; + virtual OutputBackendInterface *outputBackend() const = 0; private: const QString m_name; }; #endif diff --git a/libsound/src/capturebackendinterface.cpp b/libsound/src/capturebackendinterface.cpp index c525590..a6b3034 100644 --- a/libsound/src/capturebackendinterface.cpp +++ b/libsound/src/capturebackendinterface.cpp @@ -1,29 +1,27 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "capturebackendinterface.h" CaptureBackendInterface::CaptureBackendInterface(QObject *parent) : QObject(parent) { - } CaptureBackendInterface::~CaptureBackendInterface() { - } diff --git a/libsound/src/capturebackendinterface.h b/libsound/src/capturebackendinterface.h index d146c23..0011b3c 100644 --- a/libsound/src/capturebackendinterface.h +++ b/libsound/src/capturebackendinterface.h @@ -1,43 +1,41 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef CAPTUREBACKENDINTERFACE_H #define CAPTUREBACKENDINTERFACE_H #include "capturedevicecontroller.h" #include "libsound_export.h" #include class LIBSOUND_EXPORT CaptureBackendInterface : public QObject { Q_OBJECT public: explicit CaptureBackendInterface(QObject *parent = nullptr); virtual ~CaptureBackendInterface(); virtual void startCapture(const QString &filePath) = 0; virtual void stopCapture() = 0; virtual CaptureDeviceController::State captureState() const = 0; virtual QStringList devices() const = 0; virtual void setDevice(const QString &deviceIdentifier) = 0; }; - #endif - diff --git a/libsound/src/capturedevicecontroller.cpp b/libsound/src/capturedevicecontroller.cpp index b48ac6e..21ffa94 100644 --- a/libsound/src/capturedevicecontroller.cpp +++ b/libsound/src/capturedevicecontroller.cpp @@ -1,151 +1,147 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "capturedevicecontroller.h" -#include "capturebackendinterface.h" #include "backendinterface.h" +#include "capturebackendinterface.h" #include "libsound_debug.h" #include #include #include -#include #include +#include #include /** * \class CaptureDeviceControllerPrivate * \internal * * This is the private data class for \see CaptureDeviceController. * Note that -- even if the CaptureDeviceController is constructed before its first call -- all * devices get only configured by first instantiation of CaptureDeviceController with a call * to CaptureDeviceControllerPrivate::lazyInit(), called in CaptureDeviceController::self(). */ class CaptureDeviceControllerPrivate { public: CaptureDeviceControllerPrivate(QObject *parent) : m_parent(parent) , m_backend(nullptr) , m_initialized(false) { QStringList dirsToCheck; foreach (const QString &directory, QCoreApplication::libraryPaths()) { dirsToCheck << directory + "/artikulate/libsound"; } // load plugins QPluginLoader loader; foreach (const QString &dir, dirsToCheck) { - QVector metadataList = KPluginLoader::findPlugins(dir, - [=](const KPluginMetaData &data) - { - return data.serviceTypes().contains(QLatin1String("artikulate/libsound/backend")); - }); + QVector metadataList = KPluginLoader::findPlugins(dir, [=](const KPluginMetaData &data) { return data.serviceTypes().contains(QLatin1String("artikulate/libsound/backend")); }); foreach (const auto &metadata, metadataList) { loader.setFileName(metadata.fileName()); qCDebug(LIBSOUND_LOG) << "Load Plugin: " << metadata.name(); if (!loader.load()) { qCCritical(LIBSOUND_LOG) << "Error while loading plugin: " << metadata.name(); } KPluginFactory *factory = KPluginLoader(loader.fileName()).factory(); if (!factory) { qCCritical(LIBSOUND_LOG) << "Could not load plugin: " << metadata.name(); continue; } - BackendInterface *plugin = factory->create(parent, QList< QVariant >()); + BackendInterface *plugin = factory->create(parent, QList()); if (plugin->captureBackend()) { m_backendList.append(plugin->captureBackend()); } } } if (!m_backend && !m_backendList.isEmpty()) { m_backend = m_backendList.first(); } } ~CaptureDeviceControllerPrivate() { delete m_backend; m_backend = nullptr; } void lazyInit() { if (m_initialized) { return; } - //TODO currently nothing to do + // TODO currently nothing to do m_initialized = true; } - CaptureBackendInterface * backend() const + CaptureBackendInterface *backend() const { Q_ASSERT(m_backend); return m_backend; } QObject *m_parent; CaptureBackendInterface *m_backend; QList m_backendList; bool m_initialized; }; CaptureDeviceController::CaptureDeviceController() : d(new CaptureDeviceControllerPrivate(this)) { } CaptureDeviceController::~CaptureDeviceController() { } -CaptureDeviceController & CaptureDeviceController::self() +CaptureDeviceController &CaptureDeviceController::self() { static CaptureDeviceController instance; instance.d->lazyInit(); return instance; } void CaptureDeviceController::startCapture(const QString &filePath) { d->backend()->startCapture(filePath); emit captureStarted(); } void CaptureDeviceController::stopCapture() { d->backend()->stopCapture(); emit captureStopped(); } void CaptureDeviceController::setDevice(const QString &deviceIdentifier) { d->backend()->setDevice(deviceIdentifier); } -QList< QString > CaptureDeviceController::devices() const +QList CaptureDeviceController::devices() const { return d->backend()->devices(); } CaptureDeviceController::State CaptureDeviceController::state() const { return d->backend()->captureState(); } diff --git a/libsound/src/capturedevicecontroller.h b/libsound/src/capturedevicecontroller.h index e2fb639..b97bc2c 100644 --- a/libsound/src/capturedevicecontroller.h +++ b/libsound/src/capturedevicecontroller.h @@ -1,85 +1,79 @@ /* * Copyright 2013 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef CAPTUREDEVICECONTROLLER_H #define CAPTUREDEVICECONTROLLER_H #include "libsound_export.h" #include class CaptureDeviceControllerPrivate; /** * \class CaptureDeviceController * * This singleton class provides a controller for the sound capture device. */ class LIBSOUND_EXPORT CaptureDeviceController : public QObject { Q_OBJECT public: - enum State - { - StoppedState, - RecordingState, - PausedState - }; + enum State { StoppedState, RecordingState, PausedState }; /** * Returns self reference to the controller. First call of this method initializes * capture device controller. * * \return self reference */ - static CaptureDeviceController & self(); + static CaptureDeviceController &self(); void startCapture(const QString &filePath); CaptureDeviceController::State state() const; void stopCapture(); void setDevice(const QString &deviceIdentifier); /** * \return list of available capture devices */ QList devices() const; public Q_SLOTS: - Q_SIGNALS: void captureStarted(); void captureStopped(); private: Q_DISABLE_COPY(CaptureDeviceController) /** * \internal * Private constructor, \ref self(). */ CaptureDeviceController(); /** * Private destructor. */ ~CaptureDeviceController(); const QScopedPointer d; }; #endif diff --git a/libsound/src/outputbackendinterface.cpp b/libsound/src/outputbackendinterface.cpp index c2ef902..9e9db11 100644 --- a/libsound/src/outputbackendinterface.cpp +++ b/libsound/src/outputbackendinterface.cpp @@ -1,29 +1,27 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "outputbackendinterface.h" OutputBackendInterface::OutputBackendInterface(QObject *parent) : QObject(parent) { - } OutputBackendInterface::~OutputBackendInterface() { - } diff --git a/libsound/src/outputbackendinterface.h b/libsound/src/outputbackendinterface.h index b65ad41..9a106fe 100644 --- a/libsound/src/outputbackendinterface.h +++ b/libsound/src/outputbackendinterface.h @@ -1,52 +1,50 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef OUTPUTBACKENDINTERFACE_H #define OUTPUTBACKENDINTERFACE_H -#include "outputdevicecontroller.h" #include "libsound_export.h" +#include "outputdevicecontroller.h" #include class LIBSOUND_EXPORT OutputBackendInterface : public QObject { Q_OBJECT public: explicit OutputBackendInterface(QObject *parent = nullptr); virtual ~OutputBackendInterface(); - virtual void setUri(const QString & uri) = 0; + virtual void setUri(const QString &uri) = 0; /** * volume as cubic value */ virtual int volume() const = 0; virtual OutputDeviceController::State state() const = 0; public Q_SLOTS: virtual void play() = 0; virtual void pause() = 0; virtual void stop() = 0; virtual void setVolume(int volume) = 0; Q_SIGNALS: void positionChanged(); void stateChanged(); }; - #endif - diff --git a/libsound/src/outputdevicecontroller.cpp b/libsound/src/outputdevicecontroller.cpp index 1445e49..3ef574c 100644 --- a/libsound/src/outputdevicecontroller.cpp +++ b/libsound/src/outputdevicecontroller.cpp @@ -1,178 +1,172 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "outputdevicecontroller.h" -#include "outputbackendinterface.h" #include "backendinterface.h" +#include "outputbackendinterface.h" #include #include #include -#include #include +#include #include #include "libsound_debug.h" /** * \class OutputDeviceControllerPrivate * \internal * * This is the private data class for \see OutputDeviceController. * Note that -- even if the OutputDeviceController is constructed before its first call -- all * devices get only configured by first instantiation of OutputDeviceController with a call * to OutputDeviceControllerPrivate::lazyInit(), called in OutputDeviceController::self(). */ class OutputDeviceControllerPrivate { public: OutputDeviceControllerPrivate(OutputDeviceController *parent) : m_parent(parent) , m_backend(nullptr) , m_volume(0) , m_initialized(false) { QStringList dirsToCheck; foreach (const QString &directory, QCoreApplication::libraryPaths()) { dirsToCheck << directory + "/artikulate/libsound"; } // load plugins QPluginLoader loader; foreach (const QString &dir, dirsToCheck) { - QVector metadataList = KPluginLoader::findPlugins(dir, - [=](const KPluginMetaData &data) - { - return data.serviceTypes().contains(QLatin1String("artikulate/libsound/backend")); - }); + QVector metadataList = KPluginLoader::findPlugins(dir, [=](const KPluginMetaData &data) { return data.serviceTypes().contains(QLatin1String("artikulate/libsound/backend")); }); foreach (const auto &metadata, metadataList) { loader.setFileName(metadata.fileName()); qCDebug(LIBSOUND_LOG) << "Load Plugin: " << metadata.name(); if (!loader.load()) { qCCritical(LIBSOUND_LOG) << "Error while loading plugin: " << metadata.name(); } KPluginFactory *factory = KPluginLoader(loader.fileName()).factory(); if (!factory) { qCCritical(LIBSOUND_LOG) << "Could not load plugin:" << metadata.name(); continue; } - BackendInterface *plugin = factory->create(parent, QList< QVariant >()); + BackendInterface *plugin = factory->create(parent, QList()); if (plugin->outputBackend()) { m_backendList.append(plugin->outputBackend()); } } } if (!m_backend && !m_backendList.isEmpty()) { m_backend = m_backendList.first(); } } ~OutputDeviceControllerPrivate() { delete m_backend; } void lazyInit() { if (m_initialized) { return; } - m_parent->connect(m_backend, &OutputBackendInterface::stateChanged, - m_parent, &OutputDeviceController::emitChangedState); + m_parent->connect(m_backend, &OutputBackendInterface::stateChanged, m_parent, &OutputDeviceController::emitChangedState); m_volume = m_backend->volume(); m_initialized = true; } - OutputBackendInterface * backend() const + OutputBackendInterface *backend() const { Q_ASSERT(m_backend); return m_backend; } OutputDeviceController *m_parent; OutputBackendInterface *m_backend; QList m_backendList; int m_volume; // volume as cubic value bool m_initialized; }; OutputDeviceController::OutputDeviceController() : d(new OutputDeviceControllerPrivate(this)) { - } OutputDeviceController::~OutputDeviceController() { } -OutputDeviceController & OutputDeviceController::self() +OutputDeviceController &OutputDeviceController::self() { static OutputDeviceController instance; instance.d->lazyInit(); return instance; } -void OutputDeviceController::play(const QString& filePath) +void OutputDeviceController::play(const QString &filePath) { d->backend()->setUri(filePath); d->backend()->setVolume(d->m_volume); d->backend()->play(); emit started(); } void OutputDeviceController::play(const QUrl &filePath) { play(filePath.toLocalFile()); } void OutputDeviceController::stop() { d->backend()->stop(); emit stopped(); } OutputDeviceController::State OutputDeviceController::state() const { return d->backend()->state(); } void OutputDeviceController::setVolume(int volume) { // backend only accepts volume, when there is a pipeline // store value here and set it when playing d->backend()->setVolume(volume); d->m_volume = volume; } int OutputDeviceController::volume() const { return d->backend()->volume(); } void OutputDeviceController::emitChangedState() { if (state() == OutputDeviceController::StoppedState) { emit stopped(); return; } if (state() == OutputDeviceController::PlayingState) { emit started(); return; } } diff --git a/libsound/src/outputdevicecontroller.h b/libsound/src/outputdevicecontroller.h index 1c013ea..342d28c 100644 --- a/libsound/src/outputdevicecontroller.h +++ b/libsound/src/outputdevicecontroller.h @@ -1,83 +1,78 @@ /* * Copyright 2013 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef OUTPUTDEVICECONTROLLER_H #define OUTPUTDEVICECONTROLLER_H #include "libsound_export.h" #include class OutputDeviceControllerPrivate; class QUrl; /** * \class OutputDeviceController * * This singleton class provides a controller for the sound output device. */ class LIBSOUND_EXPORT OutputDeviceController : public QObject { Q_OBJECT public: - enum State - { - StoppedState, - PlayingState, - PausedState - }; + enum State { StoppedState, PlayingState, PausedState }; /** * Returns self reference to the controller. First call of this method initializes * output device controller. * * \return self reference */ - static OutputDeviceController & self(); + static OutputDeviceController &self(); void play(const QString &filePath); void play(const QUrl &filePath); OutputDeviceController::State state() const; void stop(); QString currentSource() const; void setVolume(int volume); int volume() const; public Q_SLOTS: void emitChangedState(); Q_SIGNALS: void started(); void stopped(); private: Q_DISABLE_COPY(OutputDeviceController) /** * \internal * Private constructor, \ref self(). */ OutputDeviceController(); /** * Private destructor. */ ~OutputDeviceController(); const QScopedPointer d; }; #endif diff --git a/libsound/src/qtgstreamerbackend/qtgstreamerbackend.cpp b/libsound/src/qtgstreamerbackend/qtgstreamerbackend.cpp index fcd6805..3e64e3d 100644 --- a/libsound/src/qtgstreamerbackend/qtgstreamerbackend.cpp +++ b/libsound/src/qtgstreamerbackend/qtgstreamerbackend.cpp @@ -1,63 +1,60 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "qtgstreamerbackend.h" #include "qtgstreamercapturebackend.h" #include "qtgstreameroutputbackend.h" #include -K_PLUGIN_FACTORY_WITH_JSON( BackendFactory, - "qtgstreamerbackend.json", - registerPlugin();) +K_PLUGIN_FACTORY_WITH_JSON(BackendFactory, "qtgstreamerbackend.json", registerPlugin();) -QtGStreamerBackend::QtGStreamerBackend(QObject *parent, const QList< QVariant >&) +QtGStreamerBackend::QtGStreamerBackend(QObject *parent, const QList &) : BackendInterface("qtgstreamer", parent) , m_captureBackend(nullptr) , m_outputBackend(nullptr) { - } QtGStreamerBackend::~QtGStreamerBackend() { if (m_captureBackend) { m_captureBackend->deleteLater(); m_captureBackend = nullptr; } if (m_outputBackend) { m_outputBackend->deleteLater(); m_outputBackend = nullptr; } } -CaptureBackendInterface * QtGStreamerBackend::captureBackend() const +CaptureBackendInterface *QtGStreamerBackend::captureBackend() const { if (!m_captureBackend) { m_captureBackend = new QtGStreamerCaptureBackend(); } return m_captureBackend; } -OutputBackendInterface * QtGStreamerBackend::outputBackend() const +OutputBackendInterface *QtGStreamerBackend::outputBackend() const { if (!m_outputBackend) { m_outputBackend = new QtGStreamerOutputBackend(); } return m_outputBackend; } #include "qtgstreamerbackend.moc" diff --git a/libsound/src/qtgstreamerbackend/qtgstreamerbackend.h b/libsound/src/qtgstreamerbackend/qtgstreamerbackend.h index 3f81ab1..4a113b2 100644 --- a/libsound/src/qtgstreamerbackend/qtgstreamerbackend.h +++ b/libsound/src/qtgstreamerbackend/qtgstreamerbackend.h @@ -1,46 +1,44 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef GSTREAMERBACKEND_H #define GSTREAMERBACKEND_H #include "../backendinterface.h" class CaptureBackendInterface; class OutputBackendInterface; class QtGStreamerCaptureBackend; class QtGStreamerOutputBackend; class QtGStreamerBackend : public BackendInterface { Q_OBJECT public: - explicit QtGStreamerBackend(QObject *parent, const QList< QVariant >&); + explicit QtGStreamerBackend(QObject *parent, const QList &); virtual ~QtGStreamerBackend(); - CaptureBackendInterface * captureBackend() const; - OutputBackendInterface * outputBackend() const; + CaptureBackendInterface *captureBackend() const; + OutputBackendInterface *outputBackend() const; private: mutable QtGStreamerCaptureBackend *m_captureBackend; mutable QtGStreamerOutputBackend *m_outputBackend; }; #endif - - diff --git a/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.cpp b/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.cpp index f3511b6..55a7323 100644 --- a/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.cpp +++ b/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.cpp @@ -1,182 +1,182 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "qtgstreamercapturebackend.h" -#include +#include "libsound_debug.h" +#include #include -#include -#include +#include +#include #include -#include -#include +#include #include +#include #include -#include -#include "libsound_debug.h" -#include +#include +#include QtGStreamerCaptureBackend::QtGStreamerCaptureBackend() { QGst::init(); - //setup the device list + // setup the device list QGst::ElementPtr src = QGst::ElementFactory::make("autoaudiosrc"); if (!src) { qCritical() << "Failed to create element \"autoaudiosrc\". Make sure you have " - << "gstreamer-plugins-good installed"; + << "gstreamer-plugins-good installed"; return; } m_availableDevices.insert("", i18nc("default sound device", "Default")); } QtGStreamerCaptureBackend::~QtGStreamerCaptureBackend() { m_pipeline.clear(); } CaptureDeviceController::State QtGStreamerCaptureBackend::captureState() const { if (!m_pipeline) { return CaptureDeviceController::StoppedState; } switch (m_pipeline->currentState()) { - case QGst::StateNull: - return CaptureDeviceController::StoppedState; - break; - case QGst::StatePaused: - return CaptureDeviceController::RecordingState; - break; - case QGst::StatePlaying: - return CaptureDeviceController::RecordingState; - break; - default: - return CaptureDeviceController::StoppedState; + case QGst::StateNull: + return CaptureDeviceController::StoppedState; + break; + case QGst::StatePaused: + return CaptureDeviceController::RecordingState; + break; + case QGst::StatePlaying: + return CaptureDeviceController::RecordingState; + break; + default: + return CaptureDeviceController::StoppedState; } } QGst::BinPtr QtGStreamerCaptureBackend::createAudioSrcBin() { QGst::BinPtr audioBin; try { - audioBin = QGst::Bin::fromDescription("autoaudiosrc name=\"audiosrc\" ! audioconvert ! " - "audioresample ! audiorate ! vorbisenc name=enc quality=0.6 ! queue"); + audioBin = QGst::Bin::fromDescription( + "autoaudiosrc name=\"audiosrc\" ! audioconvert ! " + "audioresample ! audiorate ! vorbisenc name=enc quality=0.6 ! queue"); } catch (const QGlib::Error &error) { qCritical() << "Failed to create audio source bin:" << error; return QGst::BinPtr(); } QGst::ElementPtr src = audioBin->getElementByName("audiosrc"); - //autoaudiosrc creates the actual source in the READY state + // autoaudiosrc creates the actual source in the READY state src->setState(QGst::StateReady); return audioBin; } -void QtGStreamerCaptureBackend::onBusMessage(const QGst::MessagePtr & message) +void QtGStreamerCaptureBackend::onBusMessage(const QGst::MessagePtr &message) { switch (message->type()) { - case QGst::MessageEos: - //got end-of-stream - stop the pipeline - qCDebug(LIBSOUND_LOG) << "EOS signal received, stopping pipeline"; - stopPipeline(); - break; - case QGst::MessageError: - //check if the pipeline exists before destroying it, - //since we could get multiple error messages - if (m_pipeline) { + case QGst::MessageEos: + // got end-of-stream - stop the pipeline + qCDebug(LIBSOUND_LOG) << "EOS signal received, stopping pipeline"; stopPipeline(); - } - qCritical() << "Pipeline Error:" - << message.staticCast()->error().message(); - break; - default: - break; + break; + case QGst::MessageError: + // check if the pipeline exists before destroying it, + // since we could get multiple error messages + if (m_pipeline) { + stopPipeline(); + } + qCritical() << "Pipeline Error:" << message.staticCast()->error().message(); + break; + default: + break; } } void QtGStreamerCaptureBackend::startCapture(const QString &filePath) { // clear pipeline if still existing if (m_pipeline) { qCWarning(LIBSOUND_LOG) << "removing forgotten pipeline"; - //send an end-of-stream event to flush metadata and cause an EosMessage to be delivered + // send an end-of-stream event to flush metadata and cause an EosMessage to be delivered m_pipeline->sendEvent(QGst::EosEvent::create()); } QGst::BinPtr audioSrcBin = createAudioSrcBin(); QGst::ElementPtr mux = QGst::ElementFactory::make("oggmux"); QGst::ElementPtr sink = QGst::ElementFactory::make("filesink"); if (!audioSrcBin || !mux || !sink) { qCritical() << "One or more elements could not be created. " - << "Verify that you have all the necessary element plugins installed."; + << "Verify that you have all the necessary element plugins installed."; return; } // set output path sink->setProperty("location", filePath); m_pipeline = QGst::Pipeline::create(); m_pipeline->add(audioSrcBin, mux, sink); - //link elements + // link elements QGst::PadPtr audioPad = mux->getRequestPad("audio_%u"); audioSrcBin->getStaticPad("src")->link(audioPad); mux->link(sink); - //connect the bus + // connect the bus m_pipeline->bus()->addSignalWatch(); QGlib::connect(m_pipeline->bus(), "message", this, &QtGStreamerCaptureBackend::onBusMessage); m_pipeline->setState(QGst::StatePlaying); } void QtGStreamerCaptureBackend::stopCapture() { - if (m_pipeline) { //pipeline exists - destroy it - //send an end-of-stream event to flush metadata and cause an EosMessage to be delivered + if (m_pipeline) { // pipeline exists - destroy it + // send an end-of-stream event to flush metadata and cause an EosMessage to be delivered m_pipeline->sendEvent(QGst::EosEvent::create()); } } void QtGStreamerCaptureBackend::stopPipeline() { if (!m_pipeline) { qCWarning(LIBSOUND_LOG) << "Stopping non-existing pipeline, aborting"; return; } m_pipeline->setState(QGst::StateNull); m_pipeline.clear(); } QStringList QtGStreamerCaptureBackend::devices() const { - //TODO qtgstreamer backend currently only provides access to default backend, + // TODO qtgstreamer backend currently only provides access to default backend, // reenable selection by using Gst::Device return m_availableDevices.values(); } -void QtGStreamerCaptureBackend::setDevice(const QString& deviceIdentifier) +void QtGStreamerCaptureBackend::setDevice(const QString &deviceIdentifier) { - //TODO add sanity check + // TODO add sanity check m_device = deviceIdentifier; } diff --git a/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.h b/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.h index b95e0d1..3dff395 100644 --- a/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.h +++ b/libsound/src/qtgstreamerbackend/qtgstreamercapturebackend.h @@ -1,54 +1,53 @@ /* * Copyright 2013 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef QTGSTREAMERCAPTUREBACKEND_H #define QTGSTREAMERCAPTUREBACKEND_H -#include "capturedevicecontroller.h" #include "capturebackendinterface.h" +#include "capturedevicecontroller.h" #include #include #include class QtGStreamerCaptureBackend : public CaptureBackendInterface { Q_OBJECT public: QtGStreamerCaptureBackend(); virtual ~QtGStreamerCaptureBackend(); void startCapture(const QString &filePath); void stopCapture(); CaptureDeviceController::State captureState() const; QStringList devices() const; void setDevice(const QString &deviceIdentifier); private: void onBusMessage(const QGst::MessagePtr &message); void stopPipeline(); QGst::BinPtr createAudioSrcBin(); QGst::PipelinePtr m_pipeline; QString m_device; QMap m_availableDevices; //!> (identifier,human readable name) }; - #endif diff --git a/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.cpp b/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.cpp index 37c3782..f7e70fc 100644 --- a/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.cpp +++ b/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.cpp @@ -1,224 +1,218 @@ /* * Copyright 2010 Marco Ballesio * Copyright 2011 Collabora Ltd. * @author George Kiagiadakis * Copyright 2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "qtgstreameroutputbackend.h" #include -#include #include #include -#include -#include #include +#include +#include +#include #include #include +#include #include -#include -#include #include +#include QtGStreamerOutputBackend::QtGStreamerOutputBackend() { QGst::init(); } QtGStreamerOutputBackend::~QtGStreamerOutputBackend() { m_pipeline.clear(); } -void QtGStreamerOutputBackend::setUri(const QString & uri) +void QtGStreamerOutputBackend::setUri(const QString &uri) { QString realUri = uri; - //if uri is not a real uri, assume it is a file path + // if uri is not a real uri, assume it is a file path if (realUri.indexOf("://") < 0) { realUri = QUrl::fromLocalFile(realUri).toEncoded(); } if (!m_pipeline) { m_pipeline = QGst::ElementFactory::make("playbin").dynamicCast(); if (m_pipeline) { - //watch the bus for messages + // watch the bus for messages QGst::BusPtr bus = m_pipeline->bus(); bus->addSignalWatch(); QGlib::connect(bus, "message", this, &QtGStreamerOutputBackend::onBusMessage); } else { qCritical() << "Failed to create the pipeline"; } } if (m_pipeline) { m_pipeline->setProperty("uri", realUri); } } QTime QtGStreamerOutputBackend::position() const { if (m_pipeline) { - //here we query the pipeline about its position - //and we request that the result is returned in time format + // here we query the pipeline about its position + // and we request that the result is returned in time format QGst::PositionQueryPtr query = QGst::PositionQuery::create(QGst::FormatTime); m_pipeline->query(query); return QGst::ClockTime(query->position()).toTime(); } else { - return QTime(0,0); + return QTime(0, 0); } } -void QtGStreamerOutputBackend::setPosition(const QTime & pos) +void QtGStreamerOutputBackend::setPosition(const QTime &pos) { - QGst::SeekEventPtr evt = QGst::SeekEvent::create( - 1.0, QGst::FormatTime, QGst::SeekFlagFlush, - QGst::SeekTypeSet, QGst::ClockTime::fromTime(pos), - QGst::SeekTypeNone, QGst::ClockTime::None - ); + QGst::SeekEventPtr evt = QGst::SeekEvent::create(1.0, QGst::FormatTime, QGst::SeekFlagFlush, QGst::SeekTypeSet, QGst::ClockTime::fromTime(pos), QGst::SeekTypeNone, QGst::ClockTime::None); m_pipeline->sendEvent(evt); } int QtGStreamerOutputBackend::volume() const { if (m_pipeline) { - QGst::StreamVolumePtr svp = - m_pipeline.dynamicCast(); + QGst::StreamVolumePtr svp = m_pipeline.dynamicCast(); if (svp) { return svp->volume(QGst::StreamVolumeFormatCubic) * 10; } } return 0; } void QtGStreamerOutputBackend::setVolume(int volume) { if (m_pipeline) { - QGst::StreamVolumePtr svp = - m_pipeline.dynamicCast(); + QGst::StreamVolumePtr svp = m_pipeline.dynamicCast(); - if(svp) { + if (svp) { svp->setVolume((double)volume / 10, QGst::StreamVolumeFormatCubic); } } } QTime QtGStreamerOutputBackend::length() const { if (m_pipeline) { - //here we query the pipeline about the content's duration - //and we request that the result is returned in time format + // here we query the pipeline about the content's duration + // and we request that the result is returned in time format QGst::DurationQueryPtr query = QGst::DurationQuery::create(QGst::FormatTime); m_pipeline->query(query); return QGst::ClockTime(query->duration()).toTime(); } else { - return QTime(0,0); + return QTime(0, 0); } } OutputDeviceController::State QtGStreamerOutputBackend::state() const { const QGst::State state = m_pipeline ? m_pipeline->currentState() : QGst::StateNull; switch (state) { - case QGst::StateNull: - return OutputDeviceController::StoppedState; - break; - case QGst::StatePaused: - return OutputDeviceController::PlayingState; - break; - case QGst::StatePlaying: - return OutputDeviceController::PlayingState; - break; - default: - return OutputDeviceController::StoppedState; + case QGst::StateNull: + return OutputDeviceController::StoppedState; + break; + case QGst::StatePaused: + return OutputDeviceController::PlayingState; + break; + case QGst::StatePlaying: + return OutputDeviceController::PlayingState; + break; + default: + return OutputDeviceController::StoppedState; } } void QtGStreamerOutputBackend::play() { if (m_pipeline) { m_pipeline->setState(QGst::StatePlaying); } } void QtGStreamerOutputBackend::pause() { if (m_pipeline) { m_pipeline->setState(QGst::StatePaused); } } void QtGStreamerOutputBackend::stop() { if (m_pipeline) { m_pipeline->setState(QGst::StateNull); - //once the pipeline stops, the bus is flushed so we will - //not receive any StateChangedMessage about this. - //so, to inform the ui, we have to emit this signal manually. + // once the pipeline stops, the bus is flushed so we will + // not receive any StateChangedMessage about this. + // so, to inform the ui, we have to emit this signal manually. Q_EMIT stateChanged(); } - //TODO this is a temporary fix: + // TODO this is a temporary fix: // the pipeline should not be cleared after every stop, but only when the backend is destructed // or specifically reset. Cause of the problem, both QtGStreamerOutputBackend is globally static // object and can be destructed _after_ the also globally static object QGlib::Private::ConnectionsStore // is destroyed. With calling QGst::Pipeline destructor by destructing QtGStreamerOutputBackend, // we get a crash. m_pipeline.clear(); } void QtGStreamerOutputBackend::onBusMessage(const QGst::MessagePtr &message) { switch (message->type()) { - case QGst::MessageEos: //End of stream. We reached the end of the file. - stop(); - break; - case QGst::MessageError: //Some error occurred. - qCritical() << message.staticCast()->error(); - stop(); - break; - case QGst::MessageStateChanged: //The element in message->source() has changed state - if (message->source() == m_pipeline) { - handlePipelineStateChange(message.staticCast()); - } - break; - default: - break; + case QGst::MessageEos: // End of stream. We reached the end of the file. + stop(); + break; + case QGst::MessageError: // Some error occurred. + qCritical() << message.staticCast()->error(); + stop(); + break; + case QGst::MessageStateChanged: // The element in message->source() has changed state + if (message->source() == m_pipeline) { + handlePipelineStateChange(message.staticCast()); + } + break; + default: + break; } } void QtGStreamerOutputBackend::handlePipelineStateChange(const QGst::StateChangedMessagePtr &scm) { switch (scm->newState()) { - case QGst::StatePlaying: - //start the timer when the pipeline starts playing - m_positionTimer.start(100); - break; - case QGst::StatePaused: - //stop the timer when the pipeline pauses - if(scm->oldState() == QGst::StatePlaying) { - m_positionTimer.stop(); - } - break; - default: - break; + case QGst::StatePlaying: + // start the timer when the pipeline starts playing + m_positionTimer.start(100); + break; + case QGst::StatePaused: + // stop the timer when the pipeline pauses + if (scm->oldState() == QGst::StatePlaying) { + m_positionTimer.stop(); + } + break; + default: + break; } Q_EMIT stateChanged(); } diff --git a/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.h b/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.h index b07c463..49cafa8 100644 --- a/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.h +++ b/libsound/src/qtgstreamerbackend/qtgstreameroutputbackend.h @@ -1,68 +1,68 @@ /* * Copyright 2010 Marco Ballesio * Copyright 2011 Collabora Ltd. * @author George Kiagiadakis * Copyright 2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef QTGSTREAMEROUTPUTBACKEND_H #define QTGSTREAMEROUTPUTBACKEND_H #include "outputbackendinterface.h" -#include -#include #include #include +#include +#include class QtGStreamerOutputBackend : public OutputBackendInterface { Q_OBJECT public: QtGStreamerOutputBackend(); virtual ~QtGStreamerOutputBackend(); - void setUri(const QString & uri); + void setUri(const QString &uri); QTime position() const; - void setPosition(const QTime & pos); + void setPosition(const QTime &pos); /** * volume as cubic value */ int volume() const; QTime length() const; OutputDeviceController::State state() const; public Q_SLOTS: void play(); void pause(); void stop(); void setVolume(int volume); Q_SIGNALS: void positionChanged(); void stateChanged(); private: void onBusMessage(const QGst::MessagePtr &message); void handlePipelineStateChange(const QGst::StateChangedMessagePtr &scm); QGst::PipelinePtr m_pipeline; QTimer m_positionTimer; }; #endif diff --git a/libsound/src/qtmultimediabackend/qtmultimediabackend.cpp b/libsound/src/qtmultimediabackend/qtmultimediabackend.cpp index d8b7533..ba9c8cc 100644 --- a/libsound/src/qtmultimediabackend/qtmultimediabackend.cpp +++ b/libsound/src/qtmultimediabackend/qtmultimediabackend.cpp @@ -1,49 +1,46 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "qtmultimediabackend.h" #include "qtmultimediacapturebackend.h" #include "qtmultimediaoutputbackend.h" #include -K_PLUGIN_FACTORY_WITH_JSON( BackendFactory, - "qtmultimediabackend.json", - registerPlugin();) +K_PLUGIN_FACTORY_WITH_JSON(BackendFactory, "qtmultimediabackend.json", registerPlugin();) -QtMultimediaBackend::QtMultimediaBackend(QObject *parent, const QList< QVariant >&) +QtMultimediaBackend::QtMultimediaBackend(QObject *parent, const QList &) : BackendInterface(QStringLiteral("qtmultimedia"), parent) , m_captureBackend(new QtMultimediaCaptureBackend(this)) , m_outputBackend(new QtMultimediaOutputBackend(this)) { - } QtMultimediaBackend::~QtMultimediaBackend() { } -CaptureBackendInterface * QtMultimediaBackend::captureBackend() const +CaptureBackendInterface *QtMultimediaBackend::captureBackend() const { return m_captureBackend; } -OutputBackendInterface * QtMultimediaBackend::outputBackend() const +OutputBackendInterface *QtMultimediaBackend::outputBackend() const { return m_outputBackend; } #include "qtmultimediabackend.moc" diff --git a/libsound/src/qtmultimediabackend/qtmultimediabackend.h b/libsound/src/qtmultimediabackend/qtmultimediabackend.h index cf13386..21f28ca 100644 --- a/libsound/src/qtmultimediabackend/qtmultimediabackend.h +++ b/libsound/src/qtmultimediabackend/qtmultimediabackend.h @@ -1,46 +1,44 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef QTMULTIMEDIABACKEND_H #define QTMULTIMEDIABACKEND_H #include "../backendinterface.h" class CaptureBackendInterface; class OutputBackendInterface; class QtMultimediaCaptureBackend; class QtMultimediaOutputBackend; class QtMultimediaBackend : public BackendInterface { Q_OBJECT public: - explicit QtMultimediaBackend(QObject *parent, const QList< QVariant >&); + explicit QtMultimediaBackend(QObject *parent, const QList &); virtual ~QtMultimediaBackend(); - CaptureBackendInterface * captureBackend() const override; - OutputBackendInterface * outputBackend() const override; + CaptureBackendInterface *captureBackend() const override; + OutputBackendInterface *outputBackend() const override; private: QtMultimediaCaptureBackend *m_captureBackend; QtMultimediaOutputBackend *m_outputBackend; }; #endif - - diff --git a/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.cpp b/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.cpp index c4f68b4..a97cc7f 100644 --- a/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.cpp +++ b/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.cpp @@ -1,84 +1,84 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "qtmultimediacapturebackend.h" #include "libsound_debug.h" #include #include #include QtMultimediaCaptureBackend::QtMultimediaCaptureBackend(QObject *parent) : CaptureBackendInterface(parent) { QAudioEncoderSettings audioSettings; QStringList availableCodecs = m_recorder.supportedAudioCodecs(); if (availableCodecs.contains(QLatin1String("audio/x-vorbis"))) { audioSettings.setCodec(QStringLiteral("audio/x-vorbis")); } else if (availableCodecs.contains(QLatin1String("audio/vorbis"))) { audioSettings.setCodec(QStringLiteral("audio/vorbis")); } else { qCWarning(LIBSOUND_LOG()) << "No vorbis codec was found for recordings"; audioSettings.setCodec(availableCodecs.first()); } qCDebug(LIBSOUND_LOG()) << "recording codec set to" << audioSettings.codec(); audioSettings.setQuality(QMultimedia::HighQuality); m_recorder.setAudioSettings(audioSettings); } CaptureDeviceController::State QtMultimediaCaptureBackend::captureState() const { switch (m_recorder.state()) { - case QMediaRecorder::StoppedState: - return CaptureDeviceController::StoppedState; - case QMediaRecorder::RecordingState: - return CaptureDeviceController::RecordingState; - case QMediaRecorder::PausedState: - return CaptureDeviceController::PausedState; + case QMediaRecorder::StoppedState: + return CaptureDeviceController::StoppedState; + case QMediaRecorder::RecordingState: + return CaptureDeviceController::RecordingState; + case QMediaRecorder::PausedState: + return CaptureDeviceController::PausedState; } Q_UNREACHABLE(); return CaptureDeviceController::StoppedState; } void QtMultimediaCaptureBackend::startCapture(const QString &filePath) { m_recorder.setOutputLocation(QUrl::fromLocalFile(filePath)); m_recorder.record(); } void QtMultimediaCaptureBackend::stopCapture() { m_recorder.stop(); } QStringList QtMultimediaCaptureBackend::devices() const { return m_recorder.audioInputs(); } void QtMultimediaCaptureBackend::setDevice(const QString &deviceIdentifier) { if (devices().contains(deviceIdentifier)) { m_recorder.setAudioInput(deviceIdentifier); } else { qCDebug(LIBSOUND_LOG) << "Could not set unknown capture device:" << deviceIdentifier; } } diff --git a/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.h b/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.h index b9e85c9..cbacad3 100644 --- a/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.h +++ b/libsound/src/qtmultimediabackend/qtmultimediacapturebackend.h @@ -1,53 +1,52 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef QTMULTIMEDIACAPTUREBACKEND_H #define QTMULTIMEDIACAPTUREBACKEND_H -#include "capturedevicecontroller.h" #include "capturebackendinterface.h" +#include "capturedevicecontroller.h" +#include #include #include -#include class QAudioRecorder; class QMediaRecorder; class QMediaObject; class QtMultimediaCaptureBackend : public CaptureBackendInterface { Q_OBJECT public: explicit QtMultimediaCaptureBackend(QObject *parent); ~QtMultimediaCaptureBackend() override = default; void startCapture(const QString &filePath) override; void stopCapture() override; CaptureDeviceController::State captureState() const override; QStringList devices() const override; void setDevice(const QString &deviceIdentifier) override; private: QAudioRecorder m_recorder; QString m_device; }; - #endif diff --git a/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.cpp b/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.cpp index affa2b2..1451053 100644 --- a/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.cpp +++ b/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.cpp @@ -1,78 +1,77 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "qtmultimediaoutputbackend.h" #include -#include #include +#include QtMultimediaOutputBackend::QtMultimediaOutputBackend(QObject *parent) : OutputBackendInterface(parent) , m_player(new QMediaPlayer) { - connect(m_player, &QMediaPlayer::stateChanged, - this, &QtMultimediaOutputBackend::stateChanged); + connect(m_player, &QMediaPlayer::stateChanged, this, &QtMultimediaOutputBackend::stateChanged); } QtMultimediaOutputBackend::~QtMultimediaOutputBackend() { m_player->deleteLater(); } void QtMultimediaOutputBackend::setUri(const QString &uri) { m_player->setMedia(QUrl::fromLocalFile(uri)); } int QtMultimediaOutputBackend::volume() const { - return m_player->volume(); //TODO check if this is really a cubic value + return m_player->volume(); // TODO check if this is really a cubic value } void QtMultimediaOutputBackend::setVolume(int volume) { - m_player->setVolume(volume); //TODO check if value is cubic + m_player->setVolume(volume); // TODO check if value is cubic } OutputDeviceController::State QtMultimediaOutputBackend::state() const { switch (m_player->state()) { - case QMediaPlayer::StoppedState: - return OutputDeviceController::StoppedState; - case QMediaPlayer::PlayingState: - return OutputDeviceController::PlayingState; - case QMediaPlayer::PausedState: - return OutputDeviceController::PausedState; + case QMediaPlayer::StoppedState: + return OutputDeviceController::StoppedState; + case QMediaPlayer::PlayingState: + return OutputDeviceController::PlayingState; + case QMediaPlayer::PausedState: + return OutputDeviceController::PausedState; } Q_UNREACHABLE(); return OutputDeviceController::StoppedState; } void QtMultimediaOutputBackend::play() { m_player->play(); } void QtMultimediaOutputBackend::pause() { m_player->pause(); } void QtMultimediaOutputBackend::stop() { m_player->stop(); } diff --git a/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.h b/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.h index a3d3530..493199e 100644 --- a/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.h +++ b/libsound/src/qtmultimediabackend/qtmultimediaoutputbackend.h @@ -1,52 +1,52 @@ /* * Copyright 2016 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef QTMULTIMEDIAOUTPUTBACKEND_H #define QTMULTIMEDIAOUTPUTBACKEND_H #include "outputbackendinterface.h" #include class QMediaPlayer; class QtMultimediaOutputBackend : public OutputBackendInterface { Q_OBJECT public: explicit QtMultimediaOutputBackend(QObject *parent = nullptr); virtual ~QtMultimediaOutputBackend(); - void setUri(const QString & uri) override; + void setUri(const QString &uri) override; /** * volume as cubic value */ int volume() const override; OutputDeviceController::State state() const override; public Q_SLOTS: void play() override; void pause() override; void stop() override; void setVolume(int volume) override; private: QMediaPlayer *m_player; }; #endif diff --git a/src/application.cpp b/src/application.cpp index 46d8657..897a19b 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,164 +1,140 @@ /* * 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/contributorrepository.h" #include "core/drawertrainingactions.h" #include "core/editorsession.h" #include "core/ieditablerepository.h" #include "core/ilanguage.h" #include "core/iresourcerepository.h" #include "core/isessionactions.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/resources/editablecourseresource.h" #include "core/resources/skeletonresource.h" #include "core/trainingaction.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 "liblearnerprofile/src/profilemanager.h" #include #include #include #include -Application::Application(int& argc, char** argv) +Application::Application(int &argc, char **argv) : QApplication(argc, argv) { registerQmlTypes(); } -IResourceRepository * Application::resourceRepository() const +IResourceRepository *Application::resourceRepository() const { return m_resourceRepository; } -IEditableRepository * Application::editableRepository() const +IEditableRepository *Application::editableRepository() const { - return qobject_cast(m_resourceRepository); + return qobject_cast(m_resourceRepository); } void Application::installResourceRepository(IResourceRepository *resourceRepository) { m_resourceRepository = resourceRepository; } 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, - "ContributorRepository", - QStringLiteral("ContributorRepository is unique object provided by the backend")); - qmlRegisterUncreatableType( - "artikulate", 1, 0, - "ProfileManager", - QStringLiteral("ProfileManager is unique object provided by the backend")); - qmlRegisterUncreatableType( - "artikulate", 1, 0, - "EditableCourseResource", - QStringLiteral("EditableCourseResource objects are backend objects")); - qmlRegisterUncreatableType( - "artikulate", 1, 0, - "SkeletonResource", - QStringLiteral("SkeletonResource objects are backend objects")); - qmlRegisterUncreatableType( - "artikulate", 1, 0, - "Phrase", - QStringLiteral("Phrase objects are backend objects")); - qmlRegisterUncreatableType( - "artikulate", 1, 0, - "Unit", - QStringLiteral("Unit objects are backend objects")); + 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, "ContributorRepository", QStringLiteral("ContributorRepository is unique object provided by the backend")); + qmlRegisterUncreatableType("artikulate", 1, 0, "ProfileManager", QStringLiteral("ProfileManager is unique object provided by the backend")); + qmlRegisterUncreatableType("artikulate", 1, 0, "EditableCourseResource", QStringLiteral("EditableCourseResource objects are backend objects")); + qmlRegisterUncreatableType("artikulate", 1, 0, "SkeletonResource", QStringLiteral("SkeletonResource objects are backend objects")); + qmlRegisterUncreatableType("artikulate", 1, 0, "Phrase", QStringLiteral("Phrase objects are backend objects")); + qmlRegisterUncreatableType("artikulate", 1, 0, "Unit", QStringLiteral("Unit objects are backend objects")); // interfaces qmlRegisterInterface("ICourse"); qmlRegisterInterface("IEditableCourse"); qmlRegisterInterface("IEditablePhrase"); qmlRegisterInterface("ILanguage"); qmlRegisterInterface("IPhrase"); qmlRegisterInterface("IEditableRepository"); qmlRegisterInterface("IResourceRepository"); qmlRegisterInterface("ISessionActions"); qmlRegisterInterface("IUnit"); // concrete instantiable types qmlRegisterType("artikulate", 1, 0, "DrawerTrainingActions"); qmlRegisterType("artikulate", 1, 0, "Icon"); qmlRegisterType("artikulate", 1, 0, "Language"); qmlRegisterType("artikulate", 1, 0, "Learner"); qmlRegisterType("artikulate", 1, 0, "LearningGoal"); qmlRegisterType("artikulate", 1, 0, "Phoneme"); qmlRegisterType("artikulate", 1, 0, "PhonemeGroup"); qmlRegisterType("artikulate", 1, 0, "Player"); qmlRegisterType("artikulate", 1, 0, "Recorder"); qmlRegisterType("artikulate", 1, 0, "TrainingAction"); // models qmlRegisterType("artikulate", 1, 0, "CourseFilterModel"); qmlRegisterType("artikulate", 1, 0, "CourseModel"); qmlRegisterType("artikulate", 1, 0, "LanguageModel"); qmlRegisterType("artikulate", 1, 0, "LanguageResourceModel"); qmlRegisterType("artikulate", 1, 0, "LearningGoalModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeGroupModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeUnitModel"); qmlRegisterType("artikulate", 1, 0, "PhraseFilterModel"); qmlRegisterType("artikulate", 1, 0, "PhraseListModel"); qmlRegisterType("artikulate", 1, 0, "PhraseModel"); qmlRegisterType("artikulate", 1, 0, "ProfileModel"); qmlRegisterType("artikulate", 1, 0, "SkeletonModel"); qmlRegisterType("artikulate", 1, 0, "UnitFilterModel"); qmlRegisterType("artikulate", 1, 0, "UnitModel"); -// qmlRegisterType("artikulate", 1, 0, "LearningProgressModel");//TODO must be ported to new trainingsession + // qmlRegisterType("artikulate", 1, 0, "LearningProgressModel");//TODO must be ported to new trainingsession } diff --git a/src/application.h b/src/application.h index fb251ee..8edd900 100644 --- a/src/application.h +++ b/src/application.h @@ -1,67 +1,66 @@ /* * Copyright 2013 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 APPLICATION_H #define APPLICATION_H #include "artikulatecore_export.h" #include class IResourceRepository; class IEditableRepository; class Application; #if defined(artikulateApp) #undef artikulateApp #endif #define artikulateApp (static_cast(QCoreApplication::instance())) class ARTIKULATECORE_EXPORT Application : public QApplication { Q_OBJECT public: explicit Application(int &argc, char **argv); /** * @brief install global course data repository to application * @param repository the concrete resource repository to install */ void installResourceRepository(IResourceRepository *repository); /** * @brief getter for global resource repository * @return the repository */ - IResourceRepository * resourceRepository() const; + IResourceRepository *resourceRepository() const; /** * @brief getter for global editable repository * @return the repository */ - IEditableRepository * editableRepository() const; + IEditableRepository *editableRepository() const; private: void registerQmlTypes(); - IResourceRepository *m_resourceRepository{ nullptr }; + IResourceRepository *m_resourceRepository {nullptr}; }; #endif diff --git a/src/core/contributorrepository.cpp b/src/core/contributorrepository.cpp index 7ae3c2f..755a1c9 100644 --- a/src/core/contributorrepository.cpp +++ b/src/core/contributorrepository.cpp @@ -1,425 +1,419 @@ /* * 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 "contributorrepository.h" #include "artikulate_debug.h" #include "language.h" -#include "unit.h" -#include "phrase.h" +#include "liblearnerprofile/src/learninggoal.h" +#include "liblearnerprofile/src/profilemanager.h" #include "phoneme.h" #include "phonemegroup.h" +#include "phrase.h" #include "resources/editablecourseresource.h" #include "resources/skeletonresource.h" -#include "liblearnerprofile/src/profilemanager.h" -#include "liblearnerprofile/src/learninggoal.h" +#include "unit.h" -#include -#include #include #include -#include +#include #include +#include +#include ContributorRepository::ContributorRepository() : IEditableRepository() { loadLanguageResources(); } ContributorRepository::ContributorRepository(QUrl storageLocation) : IEditableRepository() , m_storageLocation(std::move(storageLocation)) { loadLanguageResources(); } ContributorRepository::~ContributorRepository() = default; void ContributorRepository::loadLanguageResources() { // load language resources // all other resources are only loaded on demand QDir dir(":/artikulate/languages/"); dir.setFilter(QDir::Files | QDir::NoSymLinks); QFileInfoList list = dir.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); if (fileInfo.completeSuffix() != QLatin1String("xml")) { continue; } addLanguage(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); } } void ContributorRepository::sync() { for (auto iter = m_courses.begin(); iter != m_courses.end(); ++iter) { for (auto course : iter.value()) { course->sync(); } } for (auto skeleton : m_skeletonResources) { skeleton->sync(); } } bool ContributorRepository::modified() const { for (auto iter = m_courses.constBegin(); iter != m_courses.constEnd(); ++iter) { for (auto course : iter.value()) { if (course->isModified()) { return true; } } } for (auto const &courseRes : m_skeletonResources) { if (courseRes->isModified()) { return true; } } return false; } void ContributorRepository::addLanguage(const QUrl &languageFile) { if (m_loadedResources.contains(languageFile.toLocalFile())) { return; } auto language = Language::create(languageFile); emit languageResourceAboutToBeAdded(language, m_languages.count()); m_languages.append(language); m_loadedResources.append(languageFile.toLocalFile()); m_courses.insert(language->id(), QVector>()); emit languageResourceAdded(); } QUrl ContributorRepository::storageLocation() const { return m_storageLocation; } void ContributorRepository::setStorageLocation(const QUrl &path) { m_storageLocation = path; emit repositoryChanged(); reloadCourses(); } QVector> ContributorRepository::languages() const { return m_languages; } std::shared_ptr ContributorRepository::language(int index) const { Q_ASSERT(index >= 0 && index < m_languages.count()); return m_languages.at(index); } -ILanguage * ContributorRepository::language(LearnerProfile::LearningGoal *learningGoal) const +ILanguage *ContributorRepository::language(LearnerProfile::LearningGoal *learningGoal) const { if (!learningGoal) { return nullptr; } if (learningGoal->category() != LearnerProfile::LearningGoal::Language) { qCritical() << "Cannot translate non-language learning goal to language"; return nullptr; } for (auto language : m_languages) { if (language->id() == learningGoal->identifier()) { return language.get(); } } qCritical() << "No language registered with identifier " << learningGoal->identifier() << ": aborting"; return nullptr; } QVector> ContributorRepository::courseResources(std::shared_ptr language) { if (!language) { QVector> courses; for (auto iter = m_courses.constBegin(); iter != m_courses.constEnd(); ++iter) { courses.append(iter.value()); } return courses; } // return empty list if no course available for language if (!m_courses.contains(language->id())) { return QVector>(); } return m_courses[language->id()]; } QVector> ContributorRepository::courses() const { QVector> courses; for (const auto &courseList : m_courses) { for (const auto &course : courseList) { courses.append(course); } } return courses; } QVector> ContributorRepository::editableCourses() const { QVector> courses; for (const auto &courseList : m_courses) { for (const auto &course : courseList) { courses.append(course); } } return courses; } QVector> ContributorRepository::courses(const QString &languageId) const { if (languageId.isEmpty()) { return courses(); } QVector> courses; if (m_courses.contains(languageId)) { for (const auto &course : m_courses[languageId]) { courses.append(course); } } return courses; } std::shared_ptr ContributorRepository::editableCourse(std::shared_ptr language, int index) const { Q_ASSERT(m_courses.contains(language->id())); Q_ASSERT(index >= 0 && index < m_courses[language->id()].count()); return m_courses[language->id()].at(index); } void ContributorRepository::reloadCourseOrSkeleton(std::shared_ptr courseOrSkeleton) { if (!courseOrSkeleton) { qCritical() << "Cannot reload non-existing course"; return; } if (!courseOrSkeleton->file().isValid()) { qCritical() << "Cannot reload temporary file, aborting."; return; } // figure out if this is a course or a skeleton if (courseOrSkeleton->language()) { // only course files have a language - //TODO better add a check if this is contained in the course list + // TODO better add a check if this is contained in the course list // to catch possible errors QUrl file = courseOrSkeleton->file(); m_loadedResources.removeOne(courseOrSkeleton->file().toLocalFile()); removeCourse(courseOrSkeleton); addCourse(file); } else { for (auto resource : m_skeletonResources) { if (resource->id() == courseOrSkeleton->id()) { // TODO no reload available return; } } } } void ContributorRepository::reloadCourses() { // register skeleton resources QDir skeletonDirectory = QDir(storageLocation().toLocalFile()); skeletonDirectory.setFilter(QDir::Files | QDir::Hidden); if (!skeletonDirectory.cd(QStringLiteral("skeletons"))) { - qCritical() << "There is no subdirectory \"skeletons\" in directory " << skeletonDirectory.path() - << " cannot load skeletons."; + qCritical() << "There is no subdirectory \"skeletons\" in directory " << skeletonDirectory.path() << " cannot load skeletons."; } else { // read skeletons QFileInfoList list = skeletonDirectory.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); addSkeleton(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); } } // register contributor course files QDir courseDirectory(storageLocation().toLocalFile()); if (!courseDirectory.cd(QStringLiteral("courses"))) { - qCritical() << "There is no subdirectory \"courses\" in directory " << courseDirectory.path() - << " cannot load courses."; + qCritical() << "There is no subdirectory \"courses\" in directory " << courseDirectory.path() << " cannot load courses."; } else { // find courses courseDirectory.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList courseDirList = courseDirectory.entryInfoList(); // traverse all course directories for (const QFileInfo &info : courseDirList) { QDir courseDir = QDir(info.absoluteFilePath()); courseDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList courseLangDirList = courseDir.entryInfoList(); // traverse all language directories for each course for (const QFileInfo &langInfo : courseLangDirList) { QDir courseLangDir = QDir(langInfo.absoluteFilePath()); courseLangDir.setFilter(QDir::Files); QStringList nameFilters; nameFilters.append(QStringLiteral("*.xml")); QFileInfoList courses = courseLangDir.entryInfoList(nameFilters); // find and add course files for (const QFileInfo &courseInfo : courses) { addCourse(QUrl::fromLocalFile(courseInfo.filePath())); } } } } - //TODO this signal should only be emitted when repository was added/removed + // TODO this signal should only be emitted when repository was added/removed // yet the call to this method is very seldom and emitting it too often is not that harmful emit repositoryChanged(); } void ContributorRepository::updateCourseFromSkeleton(std::shared_ptr course) { - //TODO implement status information that are shown at mainwindow - if (course->foreignId().isEmpty()) { + // TODO implement status information that are shown at mainwindow + if (course->foreignId().isEmpty()) { qCritical() << "No skeleton ID specified, aborting update."; return; } std::shared_ptr skeleton; for (const auto &iter : m_skeletonResources) { if (iter->id() == course->foreignId()) { skeleton = iter; break; } } - if (!skeleton) { + if (!skeleton) { qCritical() << "Could not find skeleton with id " << course->foreignId() << ", aborting update."; } else { course->updateFrom(skeleton); } } std::shared_ptr ContributorRepository::addCourse(const QUrl &courseFile) { std::shared_ptr course; // skip already loaded resources if (m_loadedResources.contains(courseFile.toLocalFile())) { // TODO return existing resource } else { course = EditableCourseResource::create(courseFile, this); if (course->language() == nullptr) { qCritical() << "Could not load course, language unknown:" << courseFile.toLocalFile(); course.reset(); } else { // this is the regular case m_loadedResources.append(courseFile.toLocalFile()); const QString languageId = course->language()->id(); Q_ASSERT(!languageId.isEmpty()); if (!m_courses.contains(languageId)) { m_courses.insert(languageId, QVector>()); } emit courseAboutToBeAdded(course, m_courses[course->language()->id()].count()); m_courses[languageId].append(course); emit courseAdded(); emit languageCoursesChanged(); } } return course; } void ContributorRepository::removeCourse(std::shared_ptr course) { for (int index = 0; index < m_courses[course->language()->id()].length(); ++index) { if (m_courses[course->language()->id()].at(index) == course) { emit courseAboutToBeRemoved(index); m_courses[course->language()->id()].removeAt(index); emit courseRemoved(); return; } } } -IEditableCourse * ContributorRepository::createCourse(std::shared_ptr language, std::shared_ptr skeleton) +IEditableCourse *ContributorRepository::createCourse(std::shared_ptr language, std::shared_ptr skeleton) { // set path - QString path = QStringLiteral("%1/%2/%3/%4/%4.xml") - .arg(storageLocation().toLocalFile(), - QStringLiteral("courses"), - skeleton->id(), - language->id()); + QString path = QStringLiteral("%1/%2/%3/%4/%4.xml").arg(storageLocation().toLocalFile(), QStringLiteral("courses"), skeleton->id(), language->id()); auto course = EditableCourseResource::create(QUrl::fromLocalFile(path), this); Q_ASSERT(course); course->setId(QUuid::createUuid().toString()); course->setTitle(skeleton->title()); course->setDescription(skeleton->description()); course->setLanguage(language); course->setForeignId(skeleton->id()); return course.get(); } std::shared_ptr ContributorRepository::addSkeleton(const QUrl &file) { std::shared_ptr resource; // skip already loaded resources if (m_loadedResources.contains(file.toLocalFile())) { qCInfo(ARTIKULATE_LOG()) << "Skeleton already loaded, using known resource:" << file; for (auto skeleton : m_skeletonResources) { if (skeleton->file() == file) { resource = skeleton; break; } } } else { resource = SkeletonResource::create(file, this); m_loadedResources.append(resource->file().toLocalFile()); emit skeletonAboutToBeAdded(resource.get(), m_skeletonResources.count()); m_skeletonResources.append(resource); emit skeletonAdded(); } return resource; } void ContributorRepository::removeSkeleton(SkeletonResource *skeleton) { for (int index = 0; index < m_skeletonResources.length(); ++index) { if (m_skeletonResources.at(index)->id() == skeleton->id()) { emit skeletonAboutToBeRemoved(index, index); m_skeletonResources.removeAt(index); emit skeletonRemoved(); return; } } } QVector> ContributorRepository::skeletons() const { QVector> skeletonList; for (const auto &skeleton : m_skeletonResources) { skeletonList.append(skeleton); } return skeletonList; } diff --git a/src/core/contributorrepository.h b/src/core/contributorrepository.h index b573a7c..7145913 100644 --- a/src/core/contributorrepository.h +++ b/src/core/contributorrepository.h @@ -1,197 +1,197 @@ /* * 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 . */ #ifndef CONTRIBUTORREPOSITORY_H #define CONTRIBUTORREPOSITORY_H #include "artikulatecore_export.h" #include "ieditablerepository.h" -#include -#include -#include #include -#include +#include +#include #include #include +#include +#include #include "liblearnerprofile/src/learninggoal.h" class SkeletonResource; class EditableCourseResource; class LanguageResource; class Language; class ICourse; /** * @class ContributorRepository * This class handles the resources of a contributor. */ class ARTIKULATECORE_EXPORT ContributorRepository : public IEditableRepository { Q_OBJECT Q_INTERFACES(IResourceRepository) Q_INTERFACES(IEditableRepository) Q_PROPERTY(QUrl repositoryUrl READ storageLocation WRITE setStorageLocation NOTIFY repositoryChanged) public: explicit ContributorRepository(); explicit ContributorRepository(QUrl storageLocation); ~ContributorRepository() override; /** * save all changes to course resources */ void sync(); /** * \return \c true if any course or skeleton is modified, otherwise \c false */ bool modified() const; /** * \return path to working repository, if one is set */ QUrl storageLocation() const override; /** * Set path to central storage location * \param path the path to the storage location directory */ void setStorageLocation(const QUrl &path); QVector> languages() const override; /** * \return language by \p index */ std::shared_ptr language(int index) const; /** * \return language by \p learningGoal */ - Q_INVOKABLE ILanguage * language(LearnerProfile::LearningGoal* learningGoal) const; + Q_INVOKABLE ILanguage *language(LearnerProfile::LearningGoal *learningGoal) const; QVector> courses() const override; QVector> courses(const QString &languageId) const override; QVector> editableCourses() const override; /** * \return list of all loaded courses for language \p language */ QVector> courseResources(std::shared_ptr language); std::shared_ptr editableCourse(std::shared_ptr language, int index) const override; /** * Reset the file for this course or skeleton. * * \param course the course to be reloaded */ void reloadCourseOrSkeleton(std::shared_ptr course); /** * @brief Implementation of course resource reloading */ void reloadCourses() override; void updateCourseFromSkeleton(std::shared_ptr course) override; /** * Add language to resource manager by parsing the given language specification file. * * \param languageFile is the local XML file containing the language */ void addLanguage(const QUrl &languageFile); /** * Adds course to resource manager by parsing the given course specification file. * * \param courseFile is the local XML file containing the course * \return true if loaded successfully, otherwise false */ std::shared_ptr addCourse(const QUrl &courseFile); /** * Adds course to resource manager. If the course's language is not registered, the language * is registered by this method. * * \param resource the course resource to add to resource manager */ std::shared_ptr addCourseResource(std::unique_ptr resource); /** * Remove course from resource manager. If the course is modified its changes are NOT * written. For writing changes, the Course::sync() method must be called directly. * * \param course is the course to be removed */ void removeCourse(std::shared_ptr course); /** * Create new course for \p language and derived from \p skeleton. * * \return created course */ - Q_INVOKABLE IEditableCourse * createCourse(std::shared_ptr language, std::shared_ptr skeleton); + Q_INVOKABLE IEditableCourse *createCourse(std::shared_ptr language, std::shared_ptr skeleton); /** * Adds skeleton resource to resource manager * * \param resource the skeleton resource to add to resource manager */ std::shared_ptr addSkeleton(const QUrl &skeletonFile); /** * Remove skeleton from resource manager. If the skeleton is modified its changes are NOT * written. For writing changes, the Skeleton::sync() method must be called directly. * * \param skeleton is the skeleton to be removed */ void removeSkeleton(SkeletonResource *skeleton); QVector> skeletons() const override; Q_SIGNALS: void languageResourceAdded(); - void languageResourceAboutToBeAdded(std::shared_ptr,int); + void languageResourceAboutToBeAdded(std::shared_ptr, int); void languageResourceRemoved(); void languageResourceAboutToBeRemoved(int); void repositoryChanged(); void skeletonAdded(); - void skeletonAboutToBeAdded(ICourse*,int); + void skeletonAboutToBeAdded(ICourse *, int); void skeletonRemoved(); - void skeletonAboutToBeRemoved(int,int); + void skeletonAboutToBeRemoved(int, int); void languageCoursesChanged(); private: /** * This method loads all language files that are provided in the standard directories * for this application. */ void loadLanguageResources(); QUrl m_storageLocation; QVector> m_languages; - QMap> > m_courses; //!> (language-id, course-resource) + QMap>> m_courses; //!> (language-id, course-resource) QVector> m_skeletonResources; QStringList m_loadedResources; }; #endif diff --git a/src/core/drawertrainingactions.cpp b/src/core/drawertrainingactions.cpp index a906aba..7f9b3af 100644 --- a/src/core/drawertrainingactions.cpp +++ b/src/core/drawertrainingactions.cpp @@ -1,70 +1,70 @@ /* * 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 -#include #include +#include -DrawerTrainingActions::DrawerTrainingActions(QObject* parent) - : QObject{parent} - , m_defaultAction{new TrainingAction(i18n("Please select a course"), this)} +DrawerTrainingActions::DrawerTrainingActions(QObject *parent) + : QObject {parent} + , m_defaultAction {new TrainingAction(i18n("Please select a course"), this)} { } void DrawerTrainingActions::setSession(ISessionActions *session) { if (session == m_session) { return; } if (m_session) { 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::actionsChanged); connect(m_session, &TrainingSession::phraseChanged, this, &DrawerTrainingActions::triggerTrainingView); emit sessionChanged(); emit actionsChanged(); } -ISessionActions * DrawerTrainingActions::session() const +ISessionActions *DrawerTrainingActions::session() const { return m_session; } QList DrawerTrainingActions::actions() const { if (!m_session || m_session->trainingActions().isEmpty()) { QList list; - list << qobject_cast(m_defaultAction); + list << qobject_cast(m_defaultAction); return list; } QList actions; const auto trainingActions = m_session->trainingActions(); for (const auto &action : qAsConst(trainingActions)) { - actions.append(qobject_cast(action)); + actions.append(qobject_cast(action)); } return actions; } diff --git a/src/core/drawertrainingactions.h b/src/core/drawertrainingactions.h index c67337b..c52de95 100644 --- a/src/core/drawertrainingactions.h +++ b/src/core/drawertrainingactions.h @@ -1,55 +1,55 @@ /* * 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 "isessionactions.h" #include class Course; class ARTIKULATECORE_EXPORT DrawerTrainingActions : public QObject { Q_OBJECT Q_PROPERTY(ISessionActions *session READ session WRITE setSession NOTIFY sessionChanged) Q_PROPERTY(QList actions READ actions NOTIFY actionsChanged) public: DrawerTrainingActions(QObject *parent = nullptr); void setSession(ISessionActions *session); - ISessionActions * session() const; + ISessionActions *session() const; QList actions() const; Q_SIGNALS: void actionsChanged(); void sessionChanged(); /** * Notify that training view shall be displayed. */ void triggerTrainingView(); private: - ISessionActions *m_session{nullptr}; - TrainingAction *m_defaultAction{nullptr}; + ISessionActions *m_session {nullptr}; + TrainingAction *m_defaultAction {nullptr}; }; #endif diff --git a/src/core/editorsession.cpp b/src/core/editorsession.cpp index 77a79ca..9307a65 100644 --- a/src/core/editorsession.cpp +++ b/src/core/editorsession.cpp @@ -1,255 +1,255 @@ /* * 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 "editorsession.h" +#include "artikulate_debug.h" +#include "core/contributorrepository.h" +#include "core/iunit.h" #include "core/language.h" +#include "core/phrase.h" #include "core/resources/editablecourseresource.h" #include "core/resources/skeletonresource.h" -#include "core/unit.h" -#include "core/iunit.h" -#include "core/phrase.h" #include "core/trainingaction.h" -#include "core/contributorrepository.h" -#include "artikulate_debug.h" +#include "core/unit.h" EditorSession::EditorSession(QObject *parent) : ISessionActions(parent) { connect(this, &EditorSession::courseChanged, this, &EditorSession::skeletonModeChanged); } void EditorSession::setRepository(IEditableRepository *repository) { m_repository = repository; } bool EditorSession::skeletonMode() const { for (const auto &skeleton : m_repository->skeletons()) { if (skeleton->id() == m_course->id()) { return true; } } return false; } -ILanguage * EditorSession::language() const +ILanguage *EditorSession::language() const { if (m_course && m_course->language()) { return m_course->language().get(); } return nullptr; } IEditableCourse *EditorSession::course() const { return m_course; } void EditorSession::setCourse(IEditableCourse *course) { if (m_course == course) { return; } m_course = course; updateTrainingActions(); emit languageChanged(); emit courseChanged(); } -IUnit * EditorSession::activeUnit() const +IUnit *EditorSession::activeUnit() const { if (auto phrase = activePhrase()) { return phrase->unit().get(); } return nullptr; } void EditorSession::setActiveUnit(IUnit *unit) { // checking phrases in increasing order ensures that always the first phrase is selected for (int i = 0; i < m_actions.count(); ++i) { for (int j = 0; j < m_actions.at(i)->actions().count(); ++j) { - const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); + const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); if (unit == testPhrase->unit().get()) { if (auto action = activeAction()) { action->setChecked(false); } m_indexUnit = i; m_indexPhrase = j; if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); return; } } } } -void EditorSession::setActivePhrase(IPhrase * phrase) +void EditorSession::setActivePhrase(IPhrase *phrase) { for (int i = 0; i < m_actions.count(); ++i) { for (int j = 0; j < m_actions.at(i)->actions().count(); ++j) { - const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); + const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); if (phrase == testPhrase) { if (auto action = activeAction()) { action->setChecked(false); } m_indexUnit = i; m_indexPhrase = j; if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); return; } } } } -IPhrase * EditorSession::activePhrase() const +IPhrase *EditorSession::activePhrase() const { if (const auto action = activeAction()) { return action->phrase(); } return nullptr; } void EditorSession::switchToPreviousPhrase() { if (hasPreviousPhrase()) { if (m_indexPhrase == 0) { qCDebug(ARTIKULATE_CORE()) << "switching to previous unit"; if (m_indexUnit > 0) { --m_indexUnit; m_indexPhrase = m_actions.at(m_indexUnit)->actions().count() - 1; } } else { --m_indexPhrase; } if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); } else { - qCWarning(ARTIKULATE_CORE()) << "The is no previous phrase, aborting"; + qCWarning(ARTIKULATE_CORE()) << "The is no previous phrase, aborting"; } } void EditorSession::switchToNextPhrase() { if (hasNextPhrase()) { if (m_indexPhrase >= m_actions.at(m_indexUnit)->actions().count() - 1) { qCDebug(ARTIKULATE_CORE()) << "switching to next unit"; if (m_indexUnit < m_actions.count() - 1) { ++m_indexUnit; m_indexPhrase = 0; } } else { ++m_indexPhrase; } if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); } else { - qCWarning(ARTIKULATE_CORE()) << "The is no next phrase, aborting"; + qCWarning(ARTIKULATE_CORE()) << "The is no next phrase, aborting"; } } bool EditorSession::hasPreviousPhrase() const { return m_indexUnit > 0 || m_indexPhrase > 0; } bool EditorSession::hasNextPhrase() const { if (m_indexUnit < m_actions.count() - 1) { return true; } if (m_actions.constLast()) { if (m_indexPhrase < m_actions.constLast()->actions().count() - 1) { return true; } } return false; } void EditorSession::updateCourseFromSkeleton() { if (!m_course) { qCritical() << "Not updating course from skeleton, no one set."; return; } m_repository->updateCourseFromSkeleton(m_course->self()); } -TrainingAction * EditorSession::activeAction() const +TrainingAction *EditorSession::activeAction() const { if (m_indexUnit < 0 || m_indexPhrase < 0) { return nullptr; } - return qobject_cast(m_actions.at(m_indexUnit)->actions().at(m_indexPhrase)); + return qobject_cast(m_actions.at(m_indexUnit)->actions().at(m_indexPhrase)); } void EditorSession::updateTrainingActions() { for (const auto &action : qAsConst(m_actions)) { action->deleteLater(); } m_actions.clear(); if (!m_course) { m_indexUnit = -1; m_indexPhrase = -1; return; } const auto unitList = m_course->units(); for (const auto &unit : qAsConst(unitList)) { auto action = new TrainingAction(unit->title(), this); const auto phraseList = unit->phrases(); for (const auto &phrase : qAsConst(phraseList)) { action->appendChild(new TrainingAction(phrase, this, unit.get())); } if (action->hasChildren()) { m_actions.append(action); } else { action->deleteLater(); } } // update indices m_indexUnit = -1; m_indexPhrase = -1; if (m_course->units().count() > 0) { m_indexUnit = 0; if (m_course->units().constFirst()->phrases().count() > 0) { m_indexPhrase = 0; } } } QVector EditorSession::trainingActions() const { return m_actions; } diff --git a/src/core/editorsession.h b/src/core/editorsession.h index 65469fa..0c63de1 100644 --- a/src/core/editorsession.h +++ b/src/core/editorsession.h @@ -1,89 +1,89 @@ /* * 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 EDITORSESSION_H #define EDITORSESSION_H #include "artikulatecore_export.h" -#include "phrase.h" #include "isessionactions.h" +#include "phrase.h" class ILanguage; class IEditableCourse; class Unit; class IPhrase; class SkeletonResource; class IEditableRepository; /** * \class EditorSession */ class ARTIKULATECORE_EXPORT EditorSession : public ISessionActions { Q_OBJECT Q_INTERFACES(ISessionActions) Q_PROPERTY(bool skeletonMode READ skeletonMode NOTIFY skeletonModeChanged) /** * @brief language of the currently selected course or null if skeleton is selected */ Q_PROPERTY(ILanguage *language READ language NOTIFY languageChanged) Q_PROPERTY(IEditableCourse *course READ course WRITE setCourse NOTIFY courseChanged) Q_PROPERTY(IUnit *unit READ activeUnit NOTIFY unitChanged) Q_PROPERTY(IPhrase *phrase READ activePhrase WRITE setActivePhrase NOTIFY phraseChanged) Q_PROPERTY(bool hasNextPhrase READ hasNextPhrase NOTIFY phraseChanged) Q_PROPERTY(bool hasPreviousPhrase READ hasPreviousPhrase NOTIFY phraseChanged) public: explicit EditorSession(QObject *parent = nullptr); void setRepository(IEditableRepository *repository); bool skeletonMode() const; - ILanguage * language() const; - IEditableCourse * course() const; + ILanguage *language() const; + IEditableCourse *course() const; void setCourse(IEditableCourse *course); - IUnit * activeUnit() const; + IUnit *activeUnit() const; void setActiveUnit(IUnit *unit); - IPhrase * activePhrase() const; + IPhrase *activePhrase() const; void setActivePhrase(IPhrase *phrase) override; bool hasPreviousPhrase() const; bool hasNextPhrase() const; Q_INVOKABLE void switchToPreviousPhrase(); Q_INVOKABLE void switchToNextPhrase(); Q_INVOKABLE void updateCourseFromSkeleton(); - TrainingAction * activeAction() const override; + TrainingAction *activeAction() const override; QVector trainingActions() const override; Q_SIGNALS: void skeletonModeChanged(); void languageChanged(); void unitChanged(); private: Q_DISABLE_COPY(EditorSession) void updateTrainingActions(); - IEditableRepository * m_repository{ nullptr }; - bool m_editSkeleton{ false }; - IEditableCourse *m_course{ nullptr }; - QVector m_actions; - int m_indexUnit{-1}; - int m_indexPhrase{-1}; + IEditableRepository *m_repository {nullptr}; + bool m_editSkeleton {false}; + IEditableCourse *m_course {nullptr}; + QVector m_actions; + int m_indexUnit {-1}; + int m_indexPhrase {-1}; }; #endif diff --git a/src/core/icourse.h b/src/core/icourse.h index a518636..7d35a55 100644 --- a/src/core/icourse.h +++ b/src/core/icourse.h @@ -1,80 +1,80 @@ /* * Copyright 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 ICOURSE_H #define ICOURSE_H #include "artikulatecore_export.h" -#include #include +#include #include #include class QString; class ILanguage; class Unit; class Phoneme; class ARTIKULATECORE_EXPORT ICourse : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id NOTIFY idChanged) Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(QString i18nTitle READ i18nTitle NOTIFY titleChanged) Q_PROPERTY(QString description READ description NOTIFY descriptionChanged) Q_PROPERTY(QString languageTitle READ languageTitle CONSTANT) public: virtual ~ICourse() = default; virtual QString id() const = 0; virtual QString foreignId() const = 0; virtual QString title() const = 0; virtual QString i18nTitle() const = 0; virtual QString description() const = 0; virtual QString languageTitle() const = 0; virtual std::shared_ptr language() const = 0; /** * @brief Lazy loading unit list * @return list of units in course */ virtual QVector> units() = 0; virtual QUrl file() const = 0; protected: ICourse() : QObject() { } virtual void setSelf(std::shared_ptr course) = 0; Q_SIGNALS: void idChanged(); void titleChanged(); void descriptionChanged(); void languageChanged(); void unitAdded(); - void unitAboutToBeAdded(std::shared_ptr,int); + void unitAboutToBeAdded(std::shared_ptr, int); void unitsRemoved(); - void unitsAboutToBeRemoved(int,int); + void unitsAboutToBeRemoved(int, int); }; Q_DECLARE_INTERFACE(ICourse, "com.kde.artikulate.ICourse/1.0") #endif // COURSE_H diff --git a/src/core/ieditablecourse.h b/src/core/ieditablecourse.h index 8dfcc76..ba30938 100644 --- a/src/core/ieditablecourse.h +++ b/src/core/ieditablecourse.h @@ -1,76 +1,76 @@ /* * Copyright 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 IEDITABLECOURSE_H #define IEDITABLECOURSE_H #include "artikulatecore_export.h" #include "icourse.h" -#include #include +#include class QString; class ILanguage; class ARTIKULATECORE_EXPORT IEditableCourse : public ICourse { Q_OBJECT Q_INTERFACES(ICourse) public: virtual ~IEditableCourse() = default; virtual void setId(QString id) = 0; virtual void setForeignId(QString foreignId) = 0; virtual void setTitle(QString title) = 0; virtual void setI18nTitle(QString title) = 0; virtual void setDescription(QString description) = 0; virtual void setLanguage(std::shared_ptr language) = 0; virtual std::shared_ptr addUnit(std::shared_ptr unit) = 0; /** * @brief Export course to specified file. * @param filePath the absolute path to the export file * @return true of export finished without errors */ virtual bool exportToFile(const QUrl &filePath) const = 0; /** * @brief store editable course in file and set modified to false * @return true if no errors occurred */ virtual bool sync() = 0; /** * @brief Update course from skeleton * This method imports all units and phrases from the specified skeleton * * @param skeleton */ virtual void updateFrom(std::shared_ptr skeleton) = 0; virtual bool isModified() const = 0; virtual std::shared_ptr self() const = 0; protected: IEditableCourse() : ICourse() { } }; Q_DECLARE_INTERFACE(IEditableCourse, "com.kde.artikulate.IEditableCourse/1.0") #endif // EDITABLECOURSE_H diff --git a/src/core/ieditablephrase.h b/src/core/ieditablephrase.h index 041999d..bd36056 100644 --- a/src/core/ieditablephrase.h +++ b/src/core/ieditablephrase.h @@ -1,80 +1,76 @@ /* * Copyright 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 IEDITABLEPHRASE_H #define IEDITABLEPHRASE_H #include "artikulatecore_export.h" #include "iphrase.h" -#include #include +#include #include #include class QString; class Unit; class Phoneme; class ARTIKULATECORE_EXPORT IEditablePhrase : public IPhrase { Q_OBJECT Q_PROPERTY(QString id READ id NOTIFY idChanged) Q_PROPERTY(QString text READ text NOTIFY textChanged) Q_PROPERTY(QString i18nText READ i18nText NOTIFY i18nTextChanged) Q_PROPERTY(QString soundFileUrl READ soundFileUrl NOTIFY soundChanged) Q_PROPERTY(IPhrase::Type type READ type NOTIFY typeChanged) public: - enum class EditState { - Unknown, - Translated, - Completed - }; + enum class EditState { Unknown, Translated, Completed }; Q_ENUM(EditState) virtual ~IEditablePhrase() = default; virtual void setId(QString id) = 0; virtual void setForeignId(QString id) = 0; virtual void setText(QString text) = 0; virtual void seti18nText(QString text) = 0; virtual void setUnit(std::shared_ptr unit) = 0; virtual void setType(IPhrase::Type type) = 0; - virtual void setSoundFileUrl() = 0; //TODO revisit as a setter should have an argument + virtual void setSoundFileUrl() = 0; // TODO revisit as a setter should have an argument virtual IEditablePhrase::EditState editState() const = 0; virtual QString editStateString() const = 0; virtual void setEditState(IEditablePhrase::EditState state) = 0; virtual void setEditState(const QString &stateString) = 0; virtual void setSound(QUrl soundFile) = 0; protected: IEditablePhrase() : IPhrase() { } Q_SIGNALS: void modified(); void editStateChanged(); }; Q_DECLARE_INTERFACE(IEditablePhrase, "com.kde.artikulate.IEditablePhrase/1.0") #endif // IEDITABLEPHRASE_H diff --git a/src/core/ieditablerepository.h b/src/core/ieditablerepository.h index 6c62394..1ce9861 100644 --- a/src/core/ieditablerepository.h +++ b/src/core/ieditablerepository.h @@ -1,59 +1,59 @@ /* * Copyright 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 IEDITABLEREPOSITORY_H #define IEDITABLEREPOSITORY_H #include "artikulatecore_export.h" #include "iresourcerepository.h" #include class IEditableCourse; class ILanguage; /** * \class IEditableRepository * This interface provides a generic interface that provides just the methods and signals needed * to integrade a repository into the editing part of Artikulate. */ class ARTIKULATECORE_EXPORT IEditableRepository : public IResourceRepository { Q_OBJECT public: virtual ~IEditableRepository() = default; virtual QVector> editableCourses() const = 0; virtual std::shared_ptr editableCourse(std::shared_ptr language, int index) const = 0; virtual QVector> skeletons() const = 0; /** * Imports units and phrases from skeleton, deassociates removed ones. * * \param course the course to be updated */ virtual void updateCourseFromSkeleton(std::shared_ptr course) = 0; Q_SIGNALS: - void skeletonAboutToBeAdded(std::shared_ptr,int); + void skeletonAboutToBeAdded(std::shared_ptr, int); void skeletonAdded(); void skeletonAboutToBeRemoved(int); void skeletonRemoved(); }; Q_DECLARE_INTERFACE(IEditableRepository, "IEditableRepository") #endif diff --git a/src/core/ilanguage.h b/src/core/ilanguage.h index b8b7811..a1c49d2 100644 --- a/src/core/ilanguage.h +++ b/src/core/ilanguage.h @@ -1,64 +1,64 @@ /* * Copyright 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 ILANGUAGE_H #define ILANGUAGE_H #include "artikulatecore_export.h" -#include #include -#include #include +#include +#include class QString; class Phoneme; class PhonemeGroup; class ARTIKULATECORE_EXPORT ILanguage : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id NOTIFY idChanged) Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(QString i18nTitle READ i18nTitle NOTIFY i18nTitleChanged) public: virtual ~ILanguage() = default; virtual QString id() const = 0; virtual QString title() const = 0; virtual QString i18nTitle() const = 0; virtual QVector> phonemes() const = 0; virtual QVector> phonemeGroups() const = 0; protected: ILanguage(QObject *parent = nullptr) : QObject(parent) { } Q_SIGNALS: void idChanged(); void titleChanged(); void i18nTitleChanged(); void phonemesChanged(); void phonemeGroupsChanged(); }; Q_DECLARE_INTERFACE(ILanguage, "com.kde.artikulate.ILanguage/1.0") #endif // ILANGUAGE_H diff --git a/src/core/iphrase.h b/src/core/iphrase.h index 4b86a5f..f76cb18 100644 --- a/src/core/iphrase.h +++ b/src/core/iphrase.h @@ -1,86 +1,80 @@ /* * Copyright 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 IPHRASE_H #define IPHRASE_H #include "artikulatecore_export.h" -#include #include +#include #include #include class QString; class IUnit; class Phoneme; class ARTIKULATECORE_EXPORT IPhrase : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id NOTIFY idChanged) Q_PROPERTY(QString text READ text NOTIFY textChanged) Q_PROPERTY(QString i18nText READ i18nText NOTIFY i18nTextChanged) Q_PROPERTY(QString soundFileUrl READ soundFileUrl NOTIFY soundChanged) Q_PROPERTY(IPhrase::Type type READ type NOTIFY typeChanged) public: - enum class Type { - Word, - Expression, - Sentence, - Paragraph, - AllTypes - }; + enum class Type { Word, Expression, Sentence, Paragraph, AllTypes }; Q_ENUM(Type) virtual ~IPhrase() = default; virtual QString id() const = 0; virtual QString foreignId() const = 0; virtual QString text() const = 0; virtual QString i18nText() const = 0; virtual std::shared_ptr unit() const = 0; virtual IPhrase::Type type() const = 0; virtual QString typeString() const = 0; virtual QString soundFileUrl() const = 0; virtual QUrl sound() const = 0; virtual QVector phonemes() const = 0; virtual std::shared_ptr self() const = 0; protected: IPhrase() : QObject() { } virtual void setSelf(std::shared_ptr phrase) = 0; Q_SIGNALS: void idChanged(); void unitChanged(); void textChanged(); void i18nTextChanged(); void typeChanged(); void soundChanged(); void phonemesChanged(); }; Q_DECLARE_INTERFACE(IPhrase, "com.kde.artikulate.IPhrase/1.0") #endif // IPHRASE_H diff --git a/src/core/iresourcerepository.h b/src/core/iresourcerepository.h index ce4aadc..d95917a 100644 --- a/src/core/iresourcerepository.h +++ b/src/core/iresourcerepository.h @@ -1,78 +1,78 @@ /* * Copyright 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 IRESOURCEREPOSITORY_H #define IRESOURCEREPOSITORY_H #include "artikulatecore_export.h" -#include #include +#include class ICourse; class ILanguage; /** * \class IResourceRepository * This interface provides a generic interface that provides just the methods and signals needed * to integrade a repository into the training part of Artikulate. */ class ARTIKULATECORE_EXPORT IResourceRepository : public QObject { Q_OBJECT public: virtual ~IResourceRepository() = default; /** * \return path to working repository, if one is set */ virtual QUrl storageLocation() const = 0; /** * @return list of all loaded courses */ virtual QVector> courses() const = 0; /** * @param language to use for filtering * @return list of all loaded courses filtered by the named language */ virtual QVector> courses(const QString &languageId) const = 0; /** * @brief Requests a refresh of all resources * * Typical reasons to call this are GHNS signals */ virtual void reloadCourses() = 0; /** * \return list of all available languages */ virtual QVector> languages() const = 0; Q_SIGNALS: - void courseAboutToBeAdded(std::shared_ptr,int); + void courseAboutToBeAdded(std::shared_ptr, int); void courseAdded(); void courseAboutToBeRemoved(int); void courseRemoved(); }; Q_DECLARE_INTERFACE(IResourceRepository, "IResourceRepository") #endif diff --git a/src/core/isessionactions.h b/src/core/isessionactions.h index a2b0aea..6472537 100644 --- a/src/core/isessionactions.h +++ b/src/core/isessionactions.h @@ -1,64 +1,64 @@ /* * Copyright 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 ISESSIONACTIONS_H #define ISESSIONACTIONS_H #include "artikulatecore_export.h" #include #include class ICourse; class IPhrase; class TrainingAction; /** * \class ISessionActions * * Interface for both training and editor sessions that exposes simple iterator functionalities for a selecte course. * The interface provides all properties that are needed to create a navigatible menu. */ class ARTIKULATECORE_EXPORT ISessionActions : public QObject { Q_OBJECT public: ISessionActions(QObject *parent) : QObject(parent) { } virtual ~ISessionActions() = default; - virtual TrainingAction * activeAction() const = 0; + virtual TrainingAction *activeAction() const = 0; virtual void setActivePhrase(IPhrase *phrase) = 0; /** * \brief Return tree of training actions * * The return actions form a 2-level hierarchy: * - the first level are all units * - the unit actions may contain sub-actions, which are the phrases */ virtual QVector trainingActions() const = 0; Q_SIGNALS: void courseChanged(); void phraseChanged(); }; Q_DECLARE_INTERFACE(ISessionActions, "ISessionActions") #endif diff --git a/src/core/iunit.h b/src/core/iunit.h index b926346..f6e80dd 100644 --- a/src/core/iunit.h +++ b/src/core/iunit.h @@ -1,71 +1,71 @@ /* * Copyright 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 IUNIT_H #define IUNIT_H #include "artikulatecore_export.h" -#include #include +#include #include #include class QString; class ICourse; class IPhrase; class Phoneme; class ARTIKULATECORE_EXPORT IUnit : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id NOTIFY idChanged) Q_PROPERTY(QString title READ title NOTIFY titleChanged) public: virtual ~IUnit() = default; virtual QString id() const = 0; virtual QString foreignId() const = 0; virtual std::shared_ptr course() const = 0; virtual QString title() const = 0; virtual QVector> phrases() const = 0; virtual std::shared_ptr self() const = 0; Q_SIGNALS: void idChanged(); void titleChanged(); void courseChanged(); void displayPhraseTypeChanged(); void modified(); void phraseAdded(std::shared_ptr); - void phraseAboutToBeAdded(std::shared_ptr,int); + void phraseAboutToBeAdded(std::shared_ptr, int); void phraseRemoved(std::shared_ptr); - void phraseAboutToBeRemoved(int,int); + void phraseAboutToBeRemoved(int, int); protected: IUnit(QObject *parent = nullptr) : QObject(parent) { } virtual void setSelf(std::shared_ptr unit) = 0; }; Q_DECLARE_INTERFACE(IUnit, "com.kde.artikulate.IUnit/1.0") #endif // IUNIT_H diff --git a/src/core/language.cpp b/src/core/language.cpp index b9c2a21..703f944 100644 --- a/src/core/language.cpp +++ b/src/core/language.cpp @@ -1,159 +1,159 @@ /* * Copyright 2013 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 "language.h" +#include "artikulate_debug.h" #include "models/languagemodel.h" #include "phoneme.h" #include "phonemegroup.h" -#include "artikulate_debug.h" #include -#include -#include #include #include +#include +#include std::shared_ptr Language::create(QUrl file) { auto language = std::shared_ptr(new Language()); // load basic information from language file, but does not parse everything QXmlStreamReader xml; QFile handle(file.toLocalFile()); if (handle.open(QIODevice::ReadOnly)) { xml.setDevice(&handle); xml.readNextStartElement(); while (xml.readNext() && !xml.atEnd()) { if (xml.name() == "id") { language->setId(xml.readElementText()); } if (xml.name() == "title") { language->setTitle(xml.readElementText()); } if (xml.name() == "i18nTitle") { language->seti18nTitle(xml.readElementText()); } if (xml.name() == "phonemeGroup") { std::shared_ptr group = std::shared_ptr(new PhonemeGroup); while (xml.readNext() && !xml.atEnd() && xml.name() != "phonemeGroup") { if (xml.name() == "id") { group->setId(xml.readElementText()); } if (xml.name() == "title") { group->setTitle(xml.readElementText()); } if (xml.name() == "description") { group->setDescription(xml.readElementText()); } if (xml.name() == "phoneme") { std::unique_ptr phoneme = std::unique_ptr(new Phoneme); while (xml.readNext() && !xml.atEnd() && xml.name() != "phoneme") { if (xml.name() == "id") { phoneme->setId(xml.readElementText()); } if (xml.name() == "title") { phoneme->setTitle(xml.readElementText()); } } group->addPhoneme(std::move(phoneme)); } } language->m_phonemeGroups.append(group); } } if (xml.hasError()) { qCritical() << "Error occurred when reading Language XML file:" << file.toLocalFile(); } } xml.clear(); handle.close(); return language; } Language::Language() : ILanguage() { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } Language::~Language() = default; QString Language::id() const { return m_id; } void Language::setId(const QString &id) { if (id != m_id) { m_id = id; emit idChanged(); } } QString Language::title() const { return m_title; } void Language::setTitle(const QString &title) { if (QString::compare(title, m_title) != 0) { m_title = title; emit titleChanged(); } } QString Language::i18nTitle() const { return i18n(m_i18nTitle.toUtf8()); } void Language::seti18nTitle(const QString &title) { if (m_i18nTitle == title) { return; } m_i18nTitle = title; emit i18nTitleChanged(); } QUrl Language::file() const { return m_file; } void Language::setFile(const QUrl &file) { m_file = file; } QVector> Language::phonemes() const { QVector> list; for (auto group : m_phonemeGroups) { list << group->phonemes(); } return list; } QVector> Language::phonemeGroups() const { return m_phonemeGroups; } diff --git a/src/core/language.h b/src/core/language.h index 995744f..6e5a503 100644 --- a/src/core/language.h +++ b/src/core/language.h @@ -1,76 +1,76 @@ /* * Copyright 2013 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 LANGUAGE_H #define LANGUAGE_H #include "artikulatecore_export.h" #include "ilanguage.h" -#include #include -#include #include +#include +#include class QString; class Phoneme; class PhonemeGroup; class ARTIKULATECORE_EXPORT Language : public ILanguage { Q_OBJECT Q_INTERFACES(ILanguage) Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged) Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) Q_PROPERTY(QString i18nTitle READ i18nTitle WRITE seti18nTitle NOTIFY i18nTitleChanged) public: static std::shared_ptr create(QUrl file); ~Language() override; QString id() const override; void setId(const QString &id); QString title() const override; void seti18nTitle(const QString &title); QString i18nTitle() const override; void setTitle(const QString &title); QUrl file() const; void setFile(const QUrl &file); QVector> phonemes() const override; QVector> phonemeGroups() const override; Q_SIGNALS: void idChanged(); void titleChanged(); void i18nTitleChanged(); void phonemesChanged(); protected: explicit Language(); private: QString m_id; QString m_title; QString m_i18nTitle; QUrl m_file; QVector> m_phonemeGroups; }; #endif // LANGUAGE_H diff --git a/src/core/phoneme.h b/src/core/phoneme.h index 25420f1..b529ed8 100644 --- a/src/core/phoneme.h +++ b/src/core/phoneme.h @@ -1,57 +1,57 @@ /* * Copyright 2013 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 PHONEME_H #define PHONEME_H #include "artikulatecore_export.h" -#include #include +#include class QString; /** * \class Phoneme * Phonemes are properties that can be assigned to a Phrase to specify its pronunciation characteristics. */ class ARTIKULATECORE_EXPORT Phoneme : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged) Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) public: explicit Phoneme(QObject *parent = 0); QString id() const; void setId(const QString &id); QString title() const; void setTitle(const QString &title); signals: void idChanged(); void titleChanged(); private: Q_DISABLE_COPY(Phoneme) QString m_id; QString m_title; }; #endif // PHONEME_H diff --git a/src/core/phonemegroup.cpp b/src/core/phonemegroup.cpp index 98aff00..8e2188a 100644 --- a/src/core/phonemegroup.cpp +++ b/src/core/phonemegroup.cpp @@ -1,120 +1,118 @@ /* * Copyright 2013 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 "phonemegroup.h" #include "phoneme.h" #include "artikulate_debug.h" PhonemeGroup::PhonemeGroup() : QObject(nullptr) { } PhonemeGroup::~PhonemeGroup() { for (auto phoneme : m_phonemes) { phoneme->deleteLater(); } m_phonemes.clear(); } QString PhonemeGroup::id() const { return m_id; } void PhonemeGroup::setId(const QString &id) { if (id != m_id) { m_id = id; emit idChanged(); } } QString PhonemeGroup::title() const { return m_title; } void PhonemeGroup::setTitle(const QString &title) { if (QString::compare(title, m_title) != 0) { m_title = title; emit titleChanged(); } } QString PhonemeGroup::description() const { return m_description; } void PhonemeGroup::setDescription(const QString &description) { m_description = description; emit descriptionChanged(); } QVector> PhonemeGroup::phonemes() const { return m_phonemes; } bool PhonemeGroup::contains(std::shared_ptr phoneme) const { for (auto testPhoneme : m_phonemes) { if (QString::compare(testPhoneme->id(), phoneme->id()) == 0) { return true; } } return false; } std::shared_ptr PhonemeGroup::addPhoneme(std::unique_ptr phoneme) { std::shared_ptr newPhoneme(std::move(phoneme)); if (!contains(newPhoneme)) { m_phonemes.append(newPhoneme); - } - else { - qCWarning(ARTIKULATE_LOG) << "Phoneme identifier already registered in group "<< m_title <<", aborting"; + } else { + qCWarning(ARTIKULATE_LOG) << "Phoneme identifier already registered in group " << m_title << ", aborting"; } return std::shared_ptr(); } std::shared_ptr PhonemeGroup::addPhoneme(const QString &identifier, const QString &title) { Q_ASSERT(!identifier.isEmpty()); // check that identifier is not used for (auto phoneme : m_phonemes) { if (QString::compare(phoneme->id(), identifier) == 0) { - qCWarning(ARTIKULATE_LOG) << "Phoneme identifier " << identifier <<" already registered in group " - << m_title <<", aborting"; + qCWarning(ARTIKULATE_LOG) << "Phoneme identifier " << identifier << " already registered in group " << m_title << ", aborting"; return std::shared_ptr(); } } std::unique_ptr newPhoneme(new Phoneme); newPhoneme->setId(identifier); newPhoneme->setTitle(title); return addPhoneme(std::move(newPhoneme)); } diff --git a/src/core/phonemegroup.h b/src/core/phonemegroup.h index 7ac75e8..d8bfe4f 100644 --- a/src/core/phonemegroup.h +++ b/src/core/phonemegroup.h @@ -1,76 +1,76 @@ /* * Copyright 2013 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 PHONEMEGROUP_H #define PHONEMEGROUP_H #include "artikulatecore_export.h" -#include -#include -#include #include +#include +#include +#include class QString; class Phoneme; /** * \class PhonemeGroup */ class ARTIKULATECORE_EXPORT PhonemeGroup : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged) Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) public: explicit PhonemeGroup(); ~PhonemeGroup() override; QString id() const; void setId(const QString &id); QString title() const; void setTitle(const QString &title); QString description() const; void setDescription(const QString &description); std::shared_ptr addPhoneme(std::unique_ptr phoneme); std::shared_ptr addPhoneme(const QString &identifier, const QString &title); QVector> phonemes() const; /** * Checks by identifier comparison whether phoneme is registered in this group. * * \param poneme is the phoneme to be checked for if registered * \return true if registered, false otherwise */ bool contains(std::shared_ptr phoneme) const; Q_SIGNALS: void idChanged(); void titleChanged(); void descriptionChanged(); - void phonemeAdded(const Phoneme&); + void phonemeAdded(const Phoneme &); private: Q_DISABLE_COPY(PhonemeGroup) QString m_id; QString m_title; QString m_description; QVector> m_phonemes; }; #endif // PHONEMEGROUP_H diff --git a/src/core/phrase.cpp b/src/core/phrase.cpp index 24df74b..712ff21 100644 --- a/src/core/phrase.cpp +++ b/src/core/phrase.cpp @@ -1,351 +1,351 @@ /* * Copyright 2013 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 "phrase.h" -#include "unit.h" -#include "icourse.h" #include "artikulate_debug.h" -#include +#include "icourse.h" +#include "unit.h" #include +#include Phrase::Phrase() : IEditablePhrase() , m_type(IPhrase::Type::AllTypes) , m_editState(IEditablePhrase::EditState::Unknown) , m_trainingProgress(0) , m_skipCounter(0) , m_excludedFromUnit(false) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); connect(this, &Phrase::idChanged, this, &Phrase::modified); connect(this, &Phrase::typeChanged, this, &Phrase::modified); connect(this, &Phrase::textChanged, this, &Phrase::modified); connect(this, &Phrase::soundChanged, this, &Phrase::modified); connect(this, &Phrase::editStateChanged, this, &Phrase::modified); connect(this, &Phrase::i18nTextChanged, this, &Phrase::modified); connect(this, &Phrase::phonemesChanged, this, &Phrase::modified); connect(this, &Phrase::excludedChanged, this, &Phrase::modified); } Phrase::~Phrase() = default; std::shared_ptr Phrase::create() { std::shared_ptr phrase(new Phrase); phrase->setSelf(phrase); return phrase; } void Phrase::setSelf(std::shared_ptr self) { m_self = self; } std::shared_ptr Phrase::self() const { return m_self.lock(); } QString Phrase::id() const { return m_id; } void Phrase::setId(QString id) { if (id != m_id) { m_id = std::move(id); emit idChanged(); } } QString Phrase::foreignId() const { return m_foreignId; } void Phrase::setForeignId(QString id) { m_foreignId = std::move(id); } QString Phrase::text() const { return m_text; } void Phrase::setText(QString text) { if (QString::compare(text, m_text) != 0) { m_text = text.trimmed(); emit textChanged(); } } QString Phrase::i18nText() const { return m_i18nText; } void Phrase::seti18nText(QString text) { if (QString::compare(text, m_i18nText) != 0) { // copy unmodified original text string m_i18nText = std::move(text); emit i18nTextChanged(); } } Phrase::Type Phrase::type() const { return m_type; } QString Phrase::typeString() const { - switch(m_type) { - case IPhrase::Type::Word: - return QStringLiteral("word"); - case IPhrase::Type::Expression: - return QStringLiteral("expression"); - case IPhrase::Type::Sentence: - return QStringLiteral("sentence"); - case IPhrase::Type::Paragraph: - return QStringLiteral("paragraph"); - default: - return QStringLiteral("ERROR_UNKNOWN_TYPE"); + switch (m_type) { + case IPhrase::Type::Word: + return QStringLiteral("word"); + case IPhrase::Type::Expression: + return QStringLiteral("expression"); + case IPhrase::Type::Sentence: + return QStringLiteral("sentence"); + case IPhrase::Type::Paragraph: + return QStringLiteral("paragraph"); + default: + return QStringLiteral("ERROR_UNKNOWN_TYPE"); } } void Phrase::setType(Phrase::Type type) { if (m_type == type) { return; } m_type = type; emit typeChanged(); } void Phrase::setType(const QString &typeString) { if (typeString == QLatin1String("word")) { setType(IPhrase::Type::Word); return; } if (typeString == QLatin1String("expression")) { setType(IPhrase::Type::Expression); return; } if (typeString == QLatin1String("sentence")) { setType(IPhrase::Type::Sentence); return; } if (typeString == QLatin1String("paragraph")) { setType(IPhrase::Type::Paragraph); return; } qCWarning(ARTIKULATE_CORE()) << "Cannot set type from unknown identifier, aborting"; return; } Phrase::EditState Phrase::editState() const { return m_editState; } QString Phrase::editStateString() const { - switch(m_editState) { - case IEditablePhrase::EditState::Unknown: - return QStringLiteral("unknown"); - case IEditablePhrase::EditState::Translated: - return QStringLiteral("translated"); - case IEditablePhrase::EditState::Completed: - return QStringLiteral("completed"); + switch (m_editState) { + case IEditablePhrase::EditState::Unknown: + return QStringLiteral("unknown"); + case IEditablePhrase::EditState::Translated: + return QStringLiteral("translated"); + case IEditablePhrase::EditState::Completed: + return QStringLiteral("completed"); } Q_UNREACHABLE(); } void Phrase::setEditState(Phrase::EditState state) { if (m_editState == state) { return; } m_editState = state; emit editStateChanged(); } void Phrase::setEditState(const QString &stateString) { if (stateString.isEmpty()) { return; } if (stateString == QLatin1String("unknown")) { setEditState(IEditablePhrase::EditState::Unknown); return; } if (stateString == QLatin1String("translated")) { setEditState(IEditablePhrase::EditState::Translated); return; } if (stateString == QLatin1String("completed")) { setEditState(IEditablePhrase::EditState::Completed); return; } qCWarning(ARTIKULATE_LOG) << "Cannot set edit state from unknown identifier " << stateString << ", aborting"; return; } std::shared_ptr Phrase::unit() const { return m_unit.lock(); } void Phrase::setUnit(std::shared_ptr unit) { Q_ASSERT(unit); if (unit == m_unit.lock()) { return; } m_unit = unit; emit unitChanged(); } QUrl Phrase::sound() const { return m_nativeSoundFile; } void Phrase::setSound(QUrl soundFile) { if (!soundFile.isValid() || soundFile.isEmpty()) { qCWarning(ARTIKULATE_LOG) << "Not setting empty sound file path."; return; } m_nativeSoundFile = std::move(soundFile); emit soundChanged(); } QString Phrase::soundFileUrl() const { return m_nativeSoundFile.toLocalFile(); } QString Phrase::soundFileOutputPath() const { if (m_nativeSoundFile.isEmpty()) { QString outputDir = m_unit.lock()->course()->file().path() + '/'; - //TODO take care that this is proper ASCII + // TODO take care that this is proper ASCII return outputDir + id() + ".ogg"; } else { return soundFileUrl(); } } void Phrase::setSoundFileUrl() { if (soundFileOutputPath() != m_nativeSoundFile.toLocalFile()) { m_nativeSoundFile = QUrl::fromLocalFile(soundFileOutputPath()); emit soundChanged(); emit modified(); } } bool Phrase::isExcluded() const { return m_excludedFromUnit; } void Phrase::setExcluded(bool excluded) { if (excluded == m_excludedFromUnit) { return; } m_excludedFromUnit = excluded; emit excludedChanged(); } int Phrase::progress() const { return static_cast(m_trainingProgress); } void Phrase::setProgress(int value) { Q_ASSERT(value >= 0); if (value < 0) { value = 0; } if (m_trainingProgress == static_cast(value)) { return; } m_trainingProgress = static_cast(value); emit progressChanged(); } void Phrase::updateProgress(Phrase::Progress progress) { // logic of progress computation: // a) if skipped 3 times in a row, decrease progress // b) if done and skipped less than two times in a row, increase progress if (progress == Progress::Done) { m_skipCounter = 0; if (m_trainingProgress < 3) { ++m_trainingProgress; emit progressChanged(); } return; } if (progress == Progress::Skip) { ++m_skipCounter; if (m_skipCounter > 2 && m_trainingProgress > 0) { --m_trainingProgress; emit progressChanged(); } return; } } QVector Phrase::phonemes() const { return m_phonemes; } -bool Phrase::hasPhoneme(Phoneme* phoneme) +bool Phrase::hasPhoneme(Phoneme *phoneme) { return m_phonemes.contains(phoneme); } void Phrase::addPhoneme(Phoneme *phoneme) { if (!m_phonemes.contains(phoneme)) { m_phonemes.append(phoneme); emit phonemesChanged(); - //FIXME tell Unit to also send corresponding signal! + // FIXME tell Unit to also send corresponding signal! } } void Phrase::removePhoneme(Phoneme *phoneme) { if (m_phonemes.removeOne(phoneme)) { emit phonemesChanged(); - //FIXME tell Unit to also send corresponding signal! + // FIXME tell Unit to also send corresponding signal! } } diff --git a/src/core/phrase.h b/src/core/phrase.h index a76b96b..f9ff2c6 100644 --- a/src/core/phrase.h +++ b/src/core/phrase.h @@ -1,118 +1,115 @@ /* * Copyright 2013-2014 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 PHRASE_H #define PHRASE_H #include "artikulatecore_export.h" +#include "ieditablephrase.h" #include "iphrase.h" #include "iunit.h" -#include "ieditablephrase.h" -#include #include +#include #include #include class QString; class Phoneme; class IUnit; class QUrl; class ARTIKULATECORE_EXPORT Phrase : public IEditablePhrase { Q_OBJECT Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QString i18nText READ i18nText WRITE seti18nText NOTIFY i18nTextChanged) Q_PROPERTY(QString soundFileUrl READ soundFileUrl NOTIFY soundChanged) Q_PROPERTY(IPhrase::Type type READ type WRITE setType NOTIFY typeChanged) Q_PROPERTY(Phrase::EditState editState READ editState WRITE setEditState NOTIFY editStateChanged) Q_PROPERTY(bool excluded READ isExcluded NOTIFY excludedChanged) Q_PROPERTY(int progress READ progress NOTIFY progressChanged) public: - enum class Progress { - Skip, - Done - }; + enum class Progress { Skip, Done }; Q_ENUM(Progress) static std::shared_ptr create(); std::shared_ptr self() const override; ~Phrase() override; QString id() const override; void setId(QString id) override; QString foreignId() const override; void setForeignId(QString id) override; QString text() const override; void setText(QString text) override; QString i18nText() const override; void seti18nText(QString text) override; std::shared_ptr unit() const override; void setUnit(std::shared_ptr unit) override; IPhrase::Type type() const override; QString typeString() const override; void setType(IPhrase::Type type) override; void setType(const QString &typeString); QString soundFileUrl() const override; Q_INVOKABLE QString soundFileOutputPath() const; Q_INVOKABLE void setSoundFileUrl() override; IEditablePhrase::EditState editState() const override; QString editStateString() const override; void setEditState(IEditablePhrase::EditState state) override; void setEditState(const QString &stateString) override; QUrl sound() const override; void setSound(QUrl soundFile) override; QVector phonemes() const override; bool isExcluded() const; void setExcluded(bool excluded = false); int progress() const; void setProgress(int value); void updateProgress(Phrase::Progress progress); Q_INVOKABLE bool hasPhoneme(Phoneme *phoneme); Q_INVOKABLE void addPhoneme(Phoneme *phoneme); Q_INVOKABLE void removePhoneme(Phoneme *phoneme); Q_SIGNALS: void progressChanged(); void excludedChanged(); private: Q_DISABLE_COPY(Phrase) explicit Phrase(); void setSelf(std::shared_ptr self) override; std::weak_ptr m_self; QString m_id; QString m_foreignId; QString m_text; QString m_i18nText; IPhrase::Type m_type; EditState m_editState; std::weak_ptr m_unit; unsigned m_trainingProgress; int m_skipCounter; // count how many skips occurred since last progress update bool m_excludedFromUnit; QVector m_phonemes; QUrl m_nativeSoundFile; }; #endif // PHRASE_H diff --git a/src/core/player.cpp b/src/core/player.cpp index 1342b92..2fee453 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -1,96 +1,91 @@ /* * 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 "player.h" #include "libsound/src/outputdevicecontroller.h" -#include #include "artikulate_debug.h" -#include +#include #include +#include Player::Player(QObject *parent) : QObject(parent) , m_soundFile(QString()) , m_playbackState(StoppedState) { - } void Player::setSoundFile(const QUrl &fileUrl) { m_soundFile = fileUrl; emit soundFileChanged(); } -void Player::setSoundFile(const QString& fileUrl) +void Player::setSoundFile(const QString &fileUrl) { OutputDeviceController::self().stop(); setSoundFile(QUrl::fromLocalFile(fileUrl)); } QString Player::soundFile() const { return m_soundFile.toLocalFile(); } Player::PlaybackState Player::state() const { return m_playbackState; } void Player::playback() { OutputDeviceController::self().disconnect(); if (!m_soundFile.isValid()) { qCritical() << "Abort playing sound, no file available"; return; } - qCDebug(ARTIKULATE_LOG) << this << "Playback sound in file "<< m_soundFile.toLocalFile(); + qCDebug(ARTIKULATE_LOG) << this << "Playback sound in file " << m_soundFile.toLocalFile(); OutputDeviceController::self().play(QUrl::fromLocalFile(m_soundFile.toLocalFile())); m_playbackState = PlayingState; connect(&OutputDeviceController::self(), &OutputDeviceController::started, this, &Player::updateState); connect(&OutputDeviceController::self(), &OutputDeviceController::stopped, this, &Player::updateState); emit stateChanged(); } void Player::stop() { OutputDeviceController::self().stop(); OutputDeviceController::self().disconnect(); m_playbackState = StoppedState; emit stateChanged(); } void Player::updateState() { - if (OutputDeviceController::self().state() == OutputDeviceController::StoppedState - && state() == PlayingState - ) { + if (OutputDeviceController::self().state() == OutputDeviceController::StoppedState && state() == PlayingState) { m_playbackState = StoppedState; emit stateChanged(); } - if (OutputDeviceController::self().state() == OutputDeviceController::PlayingState - && state() != PlayingState - ) { + if (OutputDeviceController::self().state() == OutputDeviceController::PlayingState && state() != PlayingState) { m_playbackState = PlayingState; emit stateChanged(); } } diff --git a/src/core/player.h b/src/core/player.h index e67a64c..8e54d1a 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -1,65 +1,61 @@ /* * 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 . */ #ifndef PLAYER_H #define PLAYER_H #include "artikulatecore_export.h" #include #include class ARTIKULATECORE_EXPORT Player : public QObject { Q_OBJECT Q_PROPERTY(QString soundFileUrl READ soundFile WRITE setSoundFile NOTIFY soundFileChanged) Q_PROPERTY(PlaybackState state READ state NOTIFY stateChanged) public: Q_ENUMS(PlaybackState) - enum PlaybackState { - StoppedState, - PlayingState, - PausedState - }; + enum PlaybackState { StoppedState, PlayingState, PausedState }; explicit Player(QObject *parent = nullptr); ~Player() = default; Q_INVOKABLE void playback(); Q_INVOKABLE void stop(); PlaybackState state() const; void setSoundFile(const QUrl &fileUrl); void setSoundFile(const QString &fileUrl); QString soundFile() const; Q_SIGNALS: void stateChanged(); void soundFileChanged(); private Q_SLOTS: void updateState(); private: Q_DISABLE_COPY(Player) QUrl m_soundFile; PlaybackState m_playbackState; }; #endif // PLAYER_H diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp index 76e35f4..5554f2e 100644 --- a/src/core/recorder.cpp +++ b/src/core/recorder.cpp @@ -1,101 +1,100 @@ /* * Copyright 2013 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 "recorder.h" -#include "libsound/src/capturedevicecontroller.h" #include "artikulate_debug.h" +#include "libsound/src/capturedevicecontroller.h" -#include #include -#include +#include #include +#include Recorder::Recorder(QObject *parent) : QObject(parent) , m_state(StoppedState) , m_recordingBufferFile(QDir::tempPath() + QStringLiteral("/XXXXXX.ogg")) { - } Recorder::~Recorder() { // clear resources m_recordingBufferFile.close(); } Recorder::CaptureState Recorder::state() const { return m_state; } void Recorder::startCapture() { if (CaptureDeviceController::self().state() == CaptureDeviceController::RecordingState) { qCWarning(ARTIKULATE_LOG) << "Stopped capture before starting new capture, since was still active."; CaptureDeviceController::self().stopCapture(); } m_recordingBufferFile.open(); qCDebug(ARTIKULATE_LOG) << "Start recording to temporary file " << m_recordingBufferFile.fileName(); CaptureDeviceController::self().startCapture(m_recordingBufferFile.fileName()); m_state = RecordingState; emit stateChanged(); } void Recorder::stop() { CaptureDeviceController::self().stopCapture(); m_state = StoppedState; emit stateChanged(); emit recordingFileChanged(); } QString Recorder::recordingFile() const { if (!m_recordingBufferFile.isOpen()) { return QString(); } return m_recordingBufferFile.fileName(); } void Recorder::storeToFile(const QString &path) { if (m_recordingBufferFile.isOpen()) { QFile targetFile; targetFile.setFileName(path); if (!targetFile.exists() || targetFile.remove()) { m_recordingBufferFile.copy(path); m_recordingBufferFile.close(); emit recordingFileChanged(); } else { qCritical() << "Could not save buffered sound data to file, aborting."; } } else { qCritical() << "No buffer present."; } } void Recorder::clearBuffer() { if (m_recordingBufferFile.isOpen()) { m_recordingBufferFile.close(); emit recordingFileChanged(); } } diff --git a/src/core/recorder.h b/src/core/recorder.h index 553a6e6..8ffa057 100644 --- a/src/core/recorder.h +++ b/src/core/recorder.h @@ -1,62 +1,59 @@ /* * Copyright 2013 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 RECORDER_H #define RECORDER_H #include "artikulatecore_export.h" #include -#include #include +#include class ARTIKULATECORE_EXPORT Recorder : public QObject { Q_OBJECT Q_PROPERTY(QString recordingFile READ recordingFile NOTIFY recordingFileChanged) Q_PROPERTY(CaptureState state READ state NOTIFY stateChanged) public: Q_ENUMS(CaptureState) - enum CaptureState { - StoppedState = 0, - RecordingState = 1 - }; + enum CaptureState { StoppedState = 0, RecordingState = 1 }; explicit Recorder(QObject *parent = 0); ~Recorder(); Q_INVOKABLE void startCapture(); Q_INVOKABLE void stop(); Q_INVOKABLE void storeToFile(const QString &path); Q_INVOKABLE void clearBuffer(); CaptureState state() const; QString recordingFile() const; Q_SIGNALS: void stateChanged(); void recordingFileChanged(); private: Q_DISABLE_COPY(Recorder) CaptureState m_state; QTemporaryFile m_recordingBufferFile; }; #endif // RECORDER_H diff --git a/src/core/resourcerepository.cpp b/src/core/resourcerepository.cpp index 613af81..5ce2f6e 100644 --- a/src/core/resourcerepository.cpp +++ b/src/core/resourcerepository.cpp @@ -1,160 +1,160 @@ /* * Copyright 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 "resourcerepository.h" #include "artikulate_debug.h" -#include "resources/courseresource.h" #include "core/language.h" -#include -#include +#include "resources/courseresource.h" #include #include +#include +#include ResourceRepository::ResourceRepository() : ResourceRepository(QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DataLocation).constFirst() + QStringLiteral("/courses/"))) { } ResourceRepository::ResourceRepository(const QUrl &storageLocation) : IResourceRepository() , m_storageLocation(storageLocation) { qCDebug(ARTIKULATE_CORE()) << "Repository created from with location" << m_storageLocation; // load language resources // all other resources are only loaded on demand QDir dir(":/artikulate/languages/"); dir.setFilter(QDir::Files | QDir::NoSymLinks); QFileInfoList list = dir.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); if (fileInfo.completeSuffix() != QLatin1String("xml")) { continue; } loadLanguage(fileInfo.absoluteFilePath()); } } ResourceRepository::~ResourceRepository() = default; QUrl ResourceRepository::storageLocation() const { return m_storageLocation; } QVector> ResourceRepository::courses() const { QVector> courses; for (const auto &course : m_courses) { courses.append(course); } return courses; } QVector> ResourceRepository::courses(const QString &languageId) const { QVector> courses; for (const auto &course : m_courses) { if (course->language() && course->language()->id() == languageId) { continue; } courses.append(course); } return courses; } QVector> ResourceRepository::languages() const { QVector> languages; for (const auto &language : m_languages) { if (language == nullptr) { continue; } languages.append(language); } return languages; } std::shared_ptr ResourceRepository::language(const QString &id) const { if (m_languages.contains(id)) { return m_languages.value(id); } return nullptr; } void ResourceRepository::reloadCourses() { std::function scanDirectoryForXmlCourseFiles = [this](QDir dir) { dir.setFilter(QDir::Files | QDir::NoSymLinks); QFileInfoList list = dir.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); if (fileInfo.completeSuffix() != QLatin1String("xml")) { continue; } loadCourse(fileInfo.absoluteFilePath()); } }; QDir rootDirectory = QDir(m_storageLocation.toLocalFile()); QDirIterator it(rootDirectory, QDirIterator::Subdirectories); qCInfo(ARTIKULATE_CORE()) << "Loading courses from" << rootDirectory.absolutePath(); while (it.hasNext()) { scanDirectoryForXmlCourseFiles(it.next()); } } bool ResourceRepository::loadCourse(const QString &resourceFile) { qCDebug(ARTIKULATE_CORE()) << "Loading resource" << resourceFile; // skip already loaded resources if (m_loadedCourses.contains(resourceFile)) { qCWarning(ARTIKULATE_CORE()) << "Reloading of resources not yet supported, skippen course"; return false; } auto resource = CourseResource::create(QUrl::fromLocalFile(resourceFile), this); if (resource->language() == nullptr) { qCCritical(ARTIKULATE_CORE()) << "Could not load course, language unknown:" << resourceFile; return false; } emit courseAboutToBeAdded(resource, m_courses.count() - 1); m_courses.append(resource); emit courseAdded(); m_loadedCourses.append(resourceFile); return true; } bool ResourceRepository::loadLanguage(const QString &resourceFile) { auto language = Language::create(QUrl::fromLocalFile(resourceFile)); if (!language) { qCWarning(ARTIKULATE_CORE()) << "Could not load language" << resourceFile; return false; } if (m_languages.contains(language->id())) { qCWarning(ARTIKULATE_CORE()) << "Could not load language" << resourceFile; return false; } m_languages.insert(language->id(), language); return true; } diff --git a/src/core/resourcerepository.h b/src/core/resourcerepository.h index 1a42e99..4243882 100644 --- a/src/core/resourcerepository.h +++ b/src/core/resourcerepository.h @@ -1,97 +1,97 @@ /* * 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 RESOURCEREPOSITORY_H #define RESOURCEREPOSITORY_H #include "artikulatecore_export.h" #include "iresourcerepository.h" -#include -#include #include +#include +#include #include -#include #include +#include class CourseResource; class ICourse; class Language; class LanguageResource; /** * @class ResourceRepository * * This class provides data handling of all downloaded trainingdata of a user. It dervies from the repository interface * to provide a generalized access to the data. */ class ARTIKULATECORE_EXPORT ResourceRepository : public IResourceRepository { Q_OBJECT Q_INTERFACES(IResourceRepository) public: explicit ResourceRepository(); ~ResourceRepository() override; /** * @brief Construtor for ResourceRepository object with explicitly set course folder * * @param storageLocation relative or absolute path to courses/ folder (including that directory) */ explicit ResourceRepository(const QUrl &storageLocation); /** * @return path to repository location */ QUrl storageLocation() const override; /** * @return list of available courses */ QVector> courses() const override; /** * @return list of available courses */ QVector> courses(const QString &languageId) const override; /** * @return list of all available language specifications */ QVector> languages() const override; std::shared_ptr language(const QString &id) const; public Q_SLOTS: /** * \brief updates available resources */ void reloadCourses() override; private: bool loadCourse(const QString &resourceFile); bool loadLanguage(const QString &resourceFile); QVector> m_courses; QHash> m_languages; ///>! (language-identifier, language resource) QStringList m_loadedCourses; const QUrl m_storageLocation; }; #endif // RESOURCEREPOSITORY_H diff --git a/src/core/resources/courseparser.cpp b/src/core/resources/courseparser.cpp index 6d4249e..332c182 100644 --- a/src/core/resources/courseparser.cpp +++ b/src/core/resources/courseparser.cpp @@ -1,419 +1,409 @@ /* * 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 "courseparser.h" +#include "artikulate_debug.h" #include "core/ieditablecourse.h" #include "core/language.h" -#include "core/unit.h" -#include "core/phrase.h" #include "core/phoneme.h" -#include "artikulate_debug.h" +#include "core/phrase.h" +#include "core/unit.h" -#include +#include #include +#include #include #include #include -#include #include -#include - +#include QXmlSchema CourseParser::loadXmlSchema(const QString &schemeName) { QString relPath = QStringLiteral(":/artikulate/schemes/%1.xsd").arg(schemeName); QUrl file = QUrl::fromLocalFile(relPath); QXmlSchema schema; if (file.isEmpty() || schema.load(file) == false) { qCWarning(ARTIKULATE_PARSER()) << "Schema at file " << file.toLocalFile() << " is invalid."; } return schema; } QDomDocument CourseParser::loadDomDocument(const QUrl &path, const QXmlSchema &schema) { QDomDocument document; QXmlSchemaValidator validator(schema); if (!validator.validate(path)) { qCWarning(ARTIKULATE_PARSER()) << "Schema is not valid, aborting loading of XML document:" << path.toLocalFile(); return document; } QString errorMsg; QFile file(path.toLocalFile()); if (file.open(QIODevice::ReadOnly)) { if (!document.setContent(&file, &errorMsg)) { qCWarning(ARTIKULATE_PARSER()) << errorMsg; } } else { qCWarning(ARTIKULATE_PARSER()) << "Could not open XML document " << path.toLocalFile() << " for reading, aborting."; } return document; } std::vector> CourseParser::parseUnits(const QUrl &path, QVector> phonemes) { std::vector> units; QFileInfo info(path.toLocalFile()); if (!info.exists()) { qCCritical(ARTIKULATE_PARSER()()) << "No course file available at location" << path.toLocalFile(); return units; } QXmlStreamReader xml; QFile file(path.toLocalFile()); if (file.open(QIODevice::ReadOnly)) { xml.setDevice(&file); xml.readNextStartElement(); while (!xml.atEnd() && !xml.hasError()) { - bool elementOk{ false }; + bool elementOk {false}; QXmlStreamReader::TokenType token = xml.readNext(); if (token == QXmlStreamReader::StartDocument) { continue; } if (token == QXmlStreamReader::StartElement) { if (xml.name() == "units") { continue; } else if (xml.name() == "unit") { auto unit = parseUnit(xml, path, phonemes, elementOk); if (elementOk) { units.push_back(std::move(unit)); } } } } if (xml.hasError()) { qCCritical(ARTIKULATE_PARSER()) << "Error occurred when reading Course XML file:" << path.toLocalFile(); } } else { qCCritical(ARTIKULATE_PARSER()) << "Could not open course file" << path.toLocalFile(); } xml.clear(); file.close(); return units; } std::shared_ptr CourseParser::parseUnit(QXmlStreamReader &xml, const QUrl &path, QVector> phonemes, bool &ok) { std::shared_ptr unit = Unit::create(); ok = true; - if (xml.tokenType() != QXmlStreamReader::StartElement - && xml.name() == "unit") { + if (xml.tokenType() != QXmlStreamReader::StartElement && xml.name() == "unit") { qCWarning(ARTIKULATE_PARSER()) << "Expected to parse 'unit' element, aborting here"; return unit; } xml.readNext(); while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "unit")) { if (xml.tokenType() == QXmlStreamReader::StartElement) { - bool elementOk{ false }; + bool elementOk {false}; if (xml.name() == "id") { unit->setId(parseElement(xml, elementOk)); ok &= elementOk; - } else if (xml.name() == "foreignId") { + } else if (xml.name() == "foreignId") { unit->setForeignId(parseElement(xml, elementOk)); ok &= elementOk; } else if (xml.name() == "title") { unit->setTitle(parseElement(xml, elementOk)); ok &= elementOk; } else if (xml.name() == "phrases") { // nothing to do - } - else if (xml.name() == "phrase") { + } else if (xml.name() == "phrase") { auto phrase = parsePhrase(xml, path, phonemes, elementOk); if (elementOk) { unit->addPhrase(phrase); } ok &= elementOk; } else { qCWarning(ARTIKULATE_PARSER()) << "Skipping unknown token" << xml.name(); } } xml.readNext(); } if (!ok) { qCWarning(ARTIKULATE_PARSER()) << "Errors occurred while parsing unit" << unit->title() << unit->id(); } return unit; } std::shared_ptr CourseParser::parsePhrase(QXmlStreamReader &xml, const QUrl &path, QVector> phonemes, bool &ok) { std::shared_ptr phrase = Phrase::create(); ok = true; - if (xml.tokenType() != QXmlStreamReader::StartElement - && xml.name() == "phrase") { + if (xml.tokenType() != QXmlStreamReader::StartElement && xml.name() == "phrase") { qCWarning(ARTIKULATE_PARSER()) << "Expected to parse 'phrase' element, aborting here"; ok = false; return phrase; } xml.readNext(); while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "phrase")) { if (xml.tokenType() == QXmlStreamReader::StartElement) { - bool elementOk{ false }; + bool elementOk {false}; if (xml.name() == "id") { phrase->setId(parseElement(xml, elementOk)); ok &= elementOk; } else if (xml.name() == "foreignId") { phrase->setForeignId(parseElement(xml, elementOk)); ok &= elementOk; } else if (xml.name() == "text") { phrase->setText(parseElement(xml, elementOk)); ok &= elementOk; } else if (xml.name() == "i18nText") { phrase->seti18nText(parseElement(xml, elementOk)); ok &= elementOk; } else if (xml.name() == "soundFile") { - phrase->setSound(QUrl::fromLocalFile( - path.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() - + '/' + parseElement(xml, elementOk))); + phrase->setSound(QUrl::fromLocalFile(path.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path() + '/' + parseElement(xml, elementOk))); ok &= elementOk; } else if (xml.name() == "phonemes") { auto parsedPhonemeIds = parsePhonemeIds(xml, elementOk); for (auto phoneme : phonemes) { if (parsedPhonemeIds.contains(phoneme->id())) { phrase->addPhoneme(phoneme.get()); } } ok &= elementOk; } else if (xml.name() == "type") { const QString type = parseElement(xml, elementOk); if (type == "word") { phrase->setType(IPhrase::Type::Word); } else if (type == "expression") { phrase->setType(IPhrase::Type::Expression); } else if (type == "sentence") { phrase->setType(IPhrase::Type::Sentence); } else if (type == "paragraph") { phrase->setType(IPhrase::Type::Paragraph); } ok &= elementOk; } else if (xml.name() == "editState") { const QString type = parseElement(xml, elementOk); if (type == "translated") { phrase->setEditState(Phrase::EditState::Translated); } else if (type == "completed") { phrase->setEditState(Phrase::EditState::Completed); } else if (type == "unknown") { phrase->setEditState(Phrase::EditState::Completed); } ok &= elementOk; } else { qCWarning(ARTIKULATE_PARSER()) << "Skipping unknown token" << xml.name(); } } xml.readNext(); } if (!ok) { qCWarning(ARTIKULATE_PARSER()) << "Errors occurred while parsing phrase" << phrase->text() << phrase->id(); } return phrase; } QStringList CourseParser::parsePhonemeIds(QXmlStreamReader &xml, bool &ok) { QStringList ids; ok = true; - if (xml.tokenType() != QXmlStreamReader::StartElement - && xml.name() == "phonemes") { + if (xml.tokenType() != QXmlStreamReader::StartElement && xml.name() == "phonemes") { qCWarning(ARTIKULATE_PARSER()) << "Expected to parse 'phonemes' element, aborting here"; ok = false; return ids; } xml.readNext(); while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "phonemes")) { xml.readNext(); if (xml.tokenType() == QXmlStreamReader::StartElement) { if (xml.name() == "phonemeID") { - bool elementOk{ false }; + bool elementOk {false}; ids.append(parseElement(xml, elementOk)); ok &= elementOk; } else { qCWarning(ARTIKULATE_PARSER()) << "Skipping unknown token" << xml.name(); } } } return ids; } -QString CourseParser::parseElement(QXmlStreamReader& xml, bool &ok) +QString CourseParser::parseElement(QXmlStreamReader &xml, bool &ok) { ok = true; if (xml.tokenType() != QXmlStreamReader::StartElement) { qCCritical(ARTIKULATE_PARSER()) << "Parsing element that does not start with a start element"; ok = false; return QString(); } QString elementName = xml.name().toString(); xml.readNext(); qCDebug(ARTIKULATE_PARSER()) << "parsed: " << elementName << " / " << xml.text().toString(); return xml.text().toString(); } - QDomDocument CourseParser::serializedDocument(std::shared_ptr course, bool trainingExport) { QDomDocument document; // prepare xml header QDomProcessingInstruction header = document.createProcessingInstruction(QStringLiteral("xml"), QStringLiteral("version=\"1.0\"")); document.appendChild(header); // create main element QDomElement root = document.createElement(QStringLiteral("course")); document.appendChild(root); QDomElement idElement = document.createElement(QStringLiteral("id")); QDomElement titleElement = document.createElement(QStringLiteral("title")); QDomElement descriptionElement = document.createElement(QStringLiteral("description")); QDomElement languageElement = document.createElement(QStringLiteral("language")); idElement.appendChild(document.createTextNode(course->id())); titleElement.appendChild(document.createTextNode(course->title())); descriptionElement.appendChild(document.createTextNode(course->description())); languageElement.appendChild(document.createTextNode(course->id())); QDomElement unitListElement = document.createElement(QStringLiteral("units")); // create units for (auto unit : course->units()) { QDomElement unitElement = document.createElement(QStringLiteral("unit")); QDomElement unitIdElement = document.createElement(QStringLiteral("id")); QDomElement unitTitleElement = document.createElement(QStringLiteral("title")); QDomElement unitPhraseListElement = document.createElement(QStringLiteral("phrases")); unitIdElement.appendChild(document.createTextNode(unit->id())); unitTitleElement.appendChild(document.createTextNode(unit->title())); // construct phrases for (auto &phrase : unit->phrases()) { if (trainingExport && phrase->soundFileUrl().isEmpty()) { continue; } unitPhraseListElement.appendChild(serializedPhrase(std::static_pointer_cast(phrase), document)); } if (trainingExport && unitPhraseListElement.childNodes().isEmpty()) { continue; } // construct the unit element unitElement.appendChild(unitIdElement); if (!unit->foreignId().isEmpty()) { QDomElement unitForeignIdElement = document.createElement(QStringLiteral("foreignId")); unitForeignIdElement.appendChild(document.createTextNode(unit->foreignId())); unitElement.appendChild(unitForeignIdElement); } unitElement.appendChild(unitTitleElement); unitElement.appendChild(unitPhraseListElement); unitListElement.appendChild(unitElement); } root.appendChild(idElement); if (!course->foreignId().isEmpty()) { QDomElement courseForeignIdElement = document.createElement(QStringLiteral("foreignId")); courseForeignIdElement.appendChild(document.createTextNode(course->foreignId())); root.appendChild(courseForeignIdElement); } root.appendChild(titleElement); root.appendChild(descriptionElement); root.appendChild(languageElement); root.appendChild(unitListElement); return document; } QDomElement CourseParser::serializedPhrase(std::shared_ptr phrase, QDomDocument &document) { QDomElement phraseElement = document.createElement(QStringLiteral("phrase")); QDomElement phraseIdElement = document.createElement(QStringLiteral("id")); QDomElement phraseTextElement = document.createElement(QStringLiteral("text")); QDomElement phrasei18nTextElement = document.createElement(QStringLiteral("i18nText")); QDomElement phraseSoundFileElement = document.createElement(QStringLiteral("soundFile")); QDomElement phraseTypeElement = document.createElement(QStringLiteral("type")); QDomElement phraseEditStateElement = document.createElement(QStringLiteral("editState")); QDomElement phrasePhonemeListElement = document.createElement(QStringLiteral("phonemes")); phraseIdElement.appendChild(document.createTextNode(phrase->id())); phraseTextElement.appendChild(document.createTextNode(phrase->text())); phrasei18nTextElement.appendChild(document.createTextNode(phrase->i18nText())); phraseSoundFileElement.appendChild(document.createTextNode(phrase->sound().fileName())); phraseTypeElement.appendChild(document.createTextNode(phrase->typeString())); phraseEditStateElement.appendChild(document.createTextNode(phrase->editStateString())); // add phonemes for (auto &phoneme : phrase->phonemes()) { QDomElement phonemeElement = document.createElement(QStringLiteral("phonemeID")); phonemeElement.appendChild(document.createTextNode(phoneme->id())); phrasePhonemeListElement.appendChild(phonemeElement); } phraseElement.appendChild(phraseIdElement); if (!phrase->foreignId().isEmpty()) { QDomElement phraseForeignIdElement = document.createElement(QStringLiteral("foreignId")); phraseForeignIdElement.appendChild(document.createTextNode(phrase->foreignId())); phraseElement.appendChild(phraseForeignIdElement); } phraseElement.appendChild(phraseTextElement); phraseElement.appendChild(phrasei18nTextElement); phraseElement.appendChild(phraseSoundFileElement); phraseElement.appendChild(phraseTypeElement); phraseElement.appendChild(phraseEditStateElement); phraseElement.appendChild(phrasePhonemeListElement); return phraseElement; } bool CourseParser::exportCourseToGhnsPackage(std::shared_ptr course, const QString &exportPath) { // filename const QString fileName = course->id() + ".tar.bz2"; KTar tar = KTar(exportPath + '/' + fileName, QStringLiteral("application/x-bzip")); if (!tar.open(QIODevice::WriteOnly)) { - qCWarning(ARTIKULATE_CORE()) << "Unable to open tar file" - << exportPath + '/' + fileName - << "in write mode, aborting."; + qCWarning(ARTIKULATE_CORE()) << "Unable to open tar file" << exportPath + '/' + fileName << "in write mode, aborting."; return false; } for (auto &unit : course->units()) { for (auto &phrase : unit->phrases()) { if (QFile::exists(phrase->soundFileUrl())) { tar.addLocalFile(phrase->soundFileUrl(), phrase->id() + ".ogg"); } } } tar.writeFile(course->id() + ".xml", CourseParser::serializedDocument(course, true).toByteArray()); tar.close(); return true; } diff --git a/src/core/resources/courseparser.h b/src/core/resources/courseparser.h index 18fa7b5..d6c0559 100644 --- a/src/core/resources/courseparser.h +++ b/src/core/resources/courseparser.h @@ -1,78 +1,77 @@ /* * 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 . */ #ifndef COURSEPARSER_H #define COURSEPARSER_H #include "artikulatecore_export.h" -#include #include +#include class IEditableCourse; class IEditablePhrase; class IUnit; class Unit; class Phrase; class Phoneme; class IResourceRepository; class QXmlSchema; class QJSonDocument; class QDomDocument; class QDomElement; class QXmlStreamReader; class QString; class QUrl; class ARTIKULATECORE_EXPORT CourseParser { - public: /** * Load XSD file given by its file name (without ".xsd" suffix). The method searches exclusively * the standard install dir for XSD files in subdirectory "schemes/". * * \param schemeName name of the Xml schema without suffix * \return loaded XML Schema */ static QXmlSchema loadXmlSchema(const QString &schemeName); /** * Load XML file given by \p file that confirms with XML schema \p scheme. * * \param path is the path to the XML file to be loaded * \param scheme is the XML schema describing the DOM * \return the loaded DOM document */ static QDomDocument loadDomDocument(const QUrl &path, const QXmlSchema &schema); - static std::vector > parseUnits(const QUrl &path, QVector> phonemes = QVector>()); + static std::vector> parseUnits(const QUrl &path, QVector> phonemes = QVector>()); static QDomDocument serializedDocument(std::shared_ptr course, bool trainingExport); static QDomElement serializedPhrase(std::shared_ptr phrase, QDomDocument &document); static bool exportCourseToGhnsPackage(std::shared_ptr course, const QString &exportPath); private: static std::shared_ptr parseUnit(QXmlStreamReader &xml, const QUrl &path, QVector> phonemes, bool &ok); static std::shared_ptr parsePhrase(QXmlStreamReader &xml, const QUrl &path, QVector> phonemes, bool &ok); static QStringList parsePhonemeIds(QXmlStreamReader &xml, bool &ok); static QString parseElement(QXmlStreamReader &xml, bool &ok); }; #endif diff --git a/src/core/resources/courseresource.cpp b/src/core/resources/courseresource.cpp index 21ff223..ac468da 100644 --- a/src/core/resources/courseresource.cpp +++ b/src/core/resources/courseresource.cpp @@ -1,295 +1,288 @@ /* * Copyright 2013-2015 Andreas Cord-Landwehr * Copyright 2013 Oindrila Gupta * * 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 "courseresource.h" -#include "courseparser.h" +#include "core/iresourcerepository.h" #include "core/language.h" -#include "core/unit.h" #include "core/phoneme.h" #include "core/phonemegroup.h" -#include "core/iresourcerepository.h" +#include "core/unit.h" +#include "courseparser.h" -#include -#include -#include -#include +#include #include #include #include -#include +#include +#include +#include +#include #include "artikulate_debug.h" class CourseResourcePrivate { public: CourseResourcePrivate() = default; ~CourseResourcePrivate(); void loadCourse(CourseResource *parent); std::weak_ptr m_self; - IResourceRepository *m_repository{ nullptr }; + IResourceRepository *m_repository {nullptr}; QUrl m_file; QString m_identifier; QString m_foreignId; QString m_title; QString m_languageId; std::shared_ptr m_language; QString m_i18nTitle; QString m_description; QVector> m_units; - bool m_courseLoaded{ false }; ///> phonemes = m_language->phonemes(); auto units = CourseParser::parseUnits(m_file, phonemes); for (auto &unit : units) { parent->addUnit(std::move(unit)); } } std::shared_ptr CourseResource::create(const QUrl &path, IResourceRepository *repository) { std::shared_ptr course(new CourseResource(path, repository)); course->setSelf(course); return course; } void CourseResource::setSelf(std::shared_ptr self) { Q_ASSERT(d->m_self.expired()); d->m_self = self; } std::shared_ptr CourseResource::self() const { Q_ASSERT(!d->m_self.expired()); return d->m_self.lock(); } CourseResource::CourseResource(const QUrl &path, IResourceRepository *repository) : ICourse() , d(new CourseResourcePrivate()) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); d->m_file = path; d->m_repository = repository; // load basic information from language file, but does not parse everything QXmlStreamReader xml; QFile file(path.toLocalFile()); if (file.open(QIODevice::ReadOnly)) { xml.setDevice(&file); xml.readNextStartElement(); while (xml.readNext() && !xml.atEnd()) { if (xml.name() == "id") { d->m_identifier = xml.readElementText(); continue; } if (xml.name() == "foreignId") { d->m_foreignId = xml.readElementText(); continue; } - //TODO i18nTitle must be implemented, currently missing and hence not parsed + // TODO i18nTitle must be implemented, currently missing and hence not parsed if (xml.name() == "title") { d->m_title = xml.readElementText(); d->m_i18nTitle = d->m_title; continue; } if (xml.name() == "description") { d->m_description = xml.readElementText(); continue; } if (xml.name() == "language") { d->m_languageId = xml.readElementText(); continue; } // quit reading when basic elements are read - if (!d->m_identifier.isEmpty() - && !d->m_title.isEmpty() - && !d->m_i18nTitle.isEmpty() - && !d->m_description.isEmpty() - && !d->m_languageId.isEmpty() - && !d->m_foreignId.isEmpty() - ) - { + if (!d->m_identifier.isEmpty() && !d->m_title.isEmpty() && !d->m_i18nTitle.isEmpty() && !d->m_description.isEmpty() && !d->m_languageId.isEmpty() && !d->m_foreignId.isEmpty()) { break; } } if (xml.hasError()) { qCritical() << "Error occurred when reading Course XML file:" << path.toLocalFile(); } } else { qCCritical(ARTIKULATE_CORE()) << "Could not open course file" << path.toLocalFile(); } xml.clear(); file.close(); // find correct language if (repository != nullptr) { for (const auto &language : repository->languages()) { if (language == nullptr) { continue; } if (language->id() == d->m_languageId) { d->m_language = language; } } } if (d->m_language == nullptr) { qCCritical(ARTIKULATE_CORE()) << "A course with an unknown language was loaded"; } } CourseResource::~CourseResource() = default; QString CourseResource::id() const { return d->m_identifier; } void CourseResource::setId(const QString &id) { if (d->m_identifier == id) { return; } d->m_identifier = id; emit idChanged(); } QString CourseResource::foreignId() const { return d->m_foreignId; } void CourseResource::setForeignId(const QString &foreignId) { if (d->m_foreignId == foreignId) { return; } d->m_foreignId = foreignId; emit foreignIdChanged(); } QString CourseResource::title() const { return d->m_title; } void CourseResource::setTitle(const QString &title) { if (d->m_title == title) { return; } d->m_title = title; emit titleChanged(); } QString CourseResource::i18nTitle() const { return d->m_i18nTitle; } void CourseResource::setI18nTitle(const QString &i18nTitle) { if (d->m_i18nTitle == i18nTitle) { return; } d->m_i18nTitle = i18nTitle; emit i18nTitleChanged(); } QString CourseResource::description() const { return d->m_description; } void CourseResource::setDescription(const QString &description) { if (d->m_description == description) { return; } d->m_description = description; emit descriptionChanged(); } std::shared_ptr CourseResource::language() const { return d->m_language; } QString CourseResource::languageTitle() const { if (d->m_language) { return d->m_language->title(); } return QString(); } void CourseResource::setLanguage(std::shared_ptr language) { if (d->m_language == language) { return; } d->m_language = language; emit languageChanged(); } std::shared_ptr CourseResource::addUnit(std::shared_ptr unit) { std::shared_ptr storedUnit(std::move(unit)); storedUnit->setCourse(self()); emit unitAboutToBeAdded(storedUnit, d->m_units.count() - 1); d->m_units.append(storedUnit); emit unitAdded(); return storedUnit; } QVector> CourseResource::units() { if (d->m_courseLoaded == false) { d->loadCourse(this); } return d->m_units; } QUrl CourseResource::file() const { return d->m_file; } diff --git a/src/core/resources/courseresource.h b/src/core/resources/courseresource.h index 4c62b78..8e6b341 100644 --- a/src/core/resources/courseresource.h +++ b/src/core/resources/courseresource.h @@ -1,120 +1,120 @@ /* * Copyright 2013 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 COURSERESOURCE_H #define COURSERESOURCE_H #include "artikulatecore_export.h" #include "core/icourse.h" -#include #include #include +#include class QString; class CourseResourcePrivate; class Unit; class Phrase; class ILanguage; class IResourceRepository; class EditableCourseResource; class ARTIKULATECORE_EXPORT CourseResource : public ICourse { Q_OBJECT Q_INTERFACES(ICourse) public: static std::shared_ptr create(const QUrl &path, IResourceRepository *repository); ~CourseResource() override; /** * \return unique identifier */ QString id() const override; void setId(const QString &id); /** * \return global ID for this course */ QString foreignId() const override; void setForeignId(const QString &foreignId); /** * \return human readable localized title */ QString title() const override; void setTitle(const QString &title); /** * \return human readable title in English */ QString i18nTitle() const override; void setI18nTitle(const QString &i18nTitle); /** * \return description text for course */ QString description() const override; void setDescription(const QString &description); /** * \return language identifier of this course */ std::shared_ptr language() const override; QString languageTitle() const override; void setLanguage(std::shared_ptr language); std::shared_ptr addUnit(std::shared_ptr unit); void sync(); QUrl file() const override; QVector> units() override; Q_SIGNALS: void idChanged(); void foreignIdChanged(); void titleChanged(); void i18nTitleChanged(); void descriptionChanged(); void languageChanged(); private: /** * Create course resource from file. */ explicit CourseResource(const QUrl &path, IResourceRepository *repository); void setSelf(std::shared_ptr self) override; std::shared_ptr self() const; const std::unique_ptr d; friend EditableCourseResource; }; #endif diff --git a/src/core/resources/editablecourseresource.cpp b/src/core/resources/editablecourseresource.cpp index 1f9b102..4960098 100644 --- a/src/core/resources/editablecourseresource.cpp +++ b/src/core/resources/editablecourseresource.cpp @@ -1,298 +1,303 @@ /* * Copyright 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 "editablecourseresource.h" #include "artikulate_debug.h" #include "core/phoneme.h" #include "core/phrase.h" #include "core/unit.h" #include "courseparser.h" -#include #include #include #include #include #include #include #include #include #include +#include EditableCourseResource::EditableCourseResource(const QUrl &path, IResourceRepository *repository) : IEditableCourse() , m_course(new CourseResource(path, repository)) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); connect(m_course.get(), &ICourse::unitAboutToBeAdded, this, &ICourse::unitAboutToBeAdded); connect(m_course.get(), &ICourse::unitAdded, this, &ICourse::unitAdded); connect(m_course.get(), &CourseResource::idChanged, this, &EditableCourseResource::idChanged); - connect(m_course.get(), &CourseResource::foreignIdChanged, this, - &EditableCourseResource::foreignIdChanged); - connect( - m_course.get(), &CourseResource::titleChanged, this, &EditableCourseResource::titleChanged); - connect(m_course.get(), &CourseResource::descriptionChanged, this, - &EditableCourseResource::descriptionChanged); - connect(m_course.get(), &CourseResource::languageChanged, this, - &EditableCourseResource::languageChanged); + connect(m_course.get(), &CourseResource::foreignIdChanged, this, &EditableCourseResource::foreignIdChanged); + connect(m_course.get(), &CourseResource::titleChanged, this, &EditableCourseResource::titleChanged); + connect(m_course.get(), &CourseResource::descriptionChanged, this, &EditableCourseResource::descriptionChanged); + connect(m_course.get(), &CourseResource::languageChanged, this, &EditableCourseResource::languageChanged); } -std::shared_ptr EditableCourseResource::create( - const QUrl &path, IResourceRepository *repository) +std::shared_ptr EditableCourseResource::create(const QUrl &path, IResourceRepository *repository) { std::shared_ptr course(new EditableCourseResource(path, repository)); course->setSelf(course); return course; } void EditableCourseResource::setSelf(std::shared_ptr self) { m_course->setSelf(self); } QString EditableCourseResource::id() const { return m_course->id(); } void EditableCourseResource::setId(QString id) { if (m_course->id() != id) { m_course->setId(id); m_modified = true; } } -QString EditableCourseResource::foreignId() const { return m_course->foreignId(); } +QString EditableCourseResource::foreignId() const +{ + return m_course->foreignId(); +} void EditableCourseResource::setForeignId(QString foreignId) { m_course->setForeignId(std::move(foreignId)); } -QString EditableCourseResource::title() const { return m_course->title(); } +QString EditableCourseResource::title() const +{ + return m_course->title(); +} void EditableCourseResource::setTitle(QString title) { if (m_course->title() != title) { m_course->setTitle(title); m_modified = true; } } -QString EditableCourseResource::i18nTitle() const { return m_course->i18nTitle(); } +QString EditableCourseResource::i18nTitle() const +{ + return m_course->i18nTitle(); +} void EditableCourseResource::setI18nTitle(QString i18nTitle) { if (m_course->i18nTitle() != i18nTitle) { m_course->setI18nTitle(i18nTitle); m_modified = true; } } -QString EditableCourseResource::description() const { return m_course->description(); } +QString EditableCourseResource::description() const +{ + return m_course->description(); +} void EditableCourseResource::setDescription(QString description) { if (m_course->description() != description) { m_course->setDescription(description); m_modified = true; } } -std::shared_ptr EditableCourseResource::language() const { return m_course->language(); } +std::shared_ptr EditableCourseResource::language() const +{ + return m_course->language(); +} QString EditableCourseResource::languageTitle() const { return m_course->languageTitle(); } void EditableCourseResource::setLanguage(std::shared_ptr language) { if (m_course->language() != language) { m_course->setLanguage(language); m_modified = true; } } QUrl EditableCourseResource::file() const { return m_course->file(); } std::shared_ptr EditableCourseResource::self() const { return std::static_pointer_cast(m_course->self()); } bool EditableCourseResource::sync() { Q_ASSERT(file().isValid()); Q_ASSERT(file().isLocalFile()); Q_ASSERT(!file().isEmpty()); // not writing back if not modified if (!m_modified) { qCDebug(ARTIKULATE_LOG()) << "Aborting sync, course was not modified."; return false; } bool ok = exportToFile(file()); if (ok) { m_modified = false; } return ok; } bool EditableCourseResource::exportToFile(const QUrl &filePath) const { // write back to file // create directories if necessary QFileInfo info(filePath.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); if (!info.exists()) { qCDebug(ARTIKULATE_LOG()) << "create xml output file directory, not existing"; QDir dir; dir.mkpath(filePath.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); } // TODO port to KSaveFile QFile file(filePath.toLocalFile()); if (!file.open(QIODevice::WriteOnly)) { - qCWarning(ARTIKULATE_LOG()) - << "Unable to open file " << file.fileName() << " in write mode, aborting."; + qCWarning(ARTIKULATE_LOG()) << "Unable to open file " << file.fileName() << " in write mode, aborting."; return false; } file.write(CourseParser::serializedDocument(self(), false).toByteArray()); return true; } std::shared_ptr EditableCourseResource::addUnit(std::shared_ptr unit) { m_modified = true; auto sharedUnit = m_course->addUnit(std::move(unit)); sharedUnit->setCourse(self()); return sharedUnit; } QVector> EditableCourseResource::units() { if (!m_unitsLoaded) { for (auto &unit : m_course->units()) { unit->setCourse(self()); } m_unitsLoaded = true; } return m_course->units(); } void EditableCourseResource::updateFrom(std::shared_ptr skeleton) { for (auto skeletonUnit : skeleton->units()) { - // find matching unit or create one std::shared_ptr matchingUnit; - auto it = std::find_if(m_course->units().cbegin(), m_course->units().cend(), - [skeletonUnit](std::shared_ptr compareUnit) { - return compareUnit->foreignId() == skeletonUnit->id(); - }); + auto it = std::find_if(m_course->units().cbegin(), m_course->units().cend(), [skeletonUnit](std::shared_ptr compareUnit) { return compareUnit->foreignId() == skeletonUnit->id(); }); if (it == m_course->units().cend()) { // import complete unit auto importUnit = Unit::create(); importUnit->setId(skeletonUnit->id()); importUnit->setForeignId(skeletonUnit->id()); importUnit->setTitle(skeletonUnit->title()); matchingUnit = m_course->addUnit(std::move(importUnit)); } else { matchingUnit = *it; } // import phrases for (auto skeletonPhrase : skeletonUnit->phrases()) { - auto it = std::find_if(matchingUnit->phrases().cbegin(), - matchingUnit->phrases().cend(), [skeletonPhrase](std::shared_ptr comparePhrase) { - return comparePhrase->foreignId() == skeletonPhrase->id(); - }); + auto it = std::find_if(matchingUnit->phrases().cbegin(), matchingUnit->phrases().cend(), [skeletonPhrase](std::shared_ptr comparePhrase) { return comparePhrase->foreignId() == skeletonPhrase->id(); }); if (it == matchingUnit->phrases().cend()) { // import complete Phrase std::shared_ptr importPhrase = Phrase::create(); importPhrase->setId(skeletonPhrase->id()); importPhrase->setForeignId(skeletonPhrase->id()); importPhrase->setText(skeletonPhrase->text()); importPhrase->seti18nText(skeletonPhrase->i18nText()); importPhrase->setType(skeletonPhrase->type()); importPhrase->setUnit(matchingUnit); matchingUnit->addPhrase(importPhrase); } } } qCInfo(ARTIKULATE_LOG()) << "Update performed!"; } -bool EditableCourseResource::isModified() const { return m_modified; } +bool EditableCourseResource::isModified() const +{ + return m_modified; +} Unit *EditableCourseResource::createUnit() { // find first unused id QStringList unitIds; for (auto unit : m_course->units()) { unitIds.append(unit->id()); } QString id = QUuid::createUuid().toString(); while (unitIds.contains(id)) { id = QUuid::createUuid().toString(); qCWarning(ARTIKULATE_LOG) << "Unit id generator has found a collision, recreating id."; } // create unit std::shared_ptr unit = Unit::create(); unit->setCourse(self()); unit->setId(id); unit->setTitle(i18n("New Unit")); auto sharedUnit = addUnit(std::move(unit)); return sharedUnit.get(); } std::shared_ptr EditableCourseResource::createPhrase(Unit *unit) { // find globally unique phrase id inside course QStringList phraseIds; for (auto unit : m_course->units()) { for (auto &phrase : unit->phrases()) { phraseIds.append(phrase->id()); } } QString id = QUuid::createUuid().toString(); while (phraseIds.contains(id)) { id = QUuid::createUuid().toString(); qCWarning(ARTIKULATE_LOG) << "Phrase id generator has found a collision, recreating id."; } // create unit std::shared_ptr phrase = Phrase::create(); phrase->setId(id); phrase->setText(QLatin1String("")); phrase->setType(IPhrase::Type::Word); unit->addPhrase(phrase); return phrase; } diff --git a/src/core/resources/editablecourseresource.h b/src/core/resources/editablecourseresource.h index edb9af8..9207f00 100644 --- a/src/core/resources/editablecourseresource.h +++ b/src/core/resources/editablecourseresource.h @@ -1,128 +1,128 @@ /* * Copyright 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 EDITABLECOURSERESOURCE_H #define EDITABLECOURSERESOURCE_H #include "artikulatecore_export.h" -#include "courseresource.h" #include "core/icourse.h" #include "core/ieditablecourse.h" +#include "courseresource.h" -#include #include #include +#include class IResourceRepository; class Course; class Unit; class Phrase; class QString; class QDomDocument; /** * @brief Decorator for CourseResource * * This decorator adds functionality to modify and write back changes of a course. */ class ARTIKULATECORE_EXPORT EditableCourseResource : public IEditableCourse { Q_OBJECT Q_INTERFACES(ICourse) Q_INTERFACES(IEditableCourse) public: static std::shared_ptr create(const QUrl &path, IResourceRepository *repository); ~EditableCourseResource() override = default; /** * \return unique identifier */ QString id() const override; void setId(QString id) override; /** * \return unique identifier */ QString foreignId() const override; void setForeignId(QString foreignId) override; /** * \return human readable localized title */ QString title() const override; void setTitle(QString title) override; /** * \return human readable title in English */ QString i18nTitle() const override; void setI18nTitle(QString i18nTitle) override; /** * \return description text for course */ QString description() const override; void setDescription(QString description) override; /** * \return language identifier of this course */ std::shared_ptr language() const override; QString languageTitle() const override; void setLanguage(std::shared_ptr language) override; bool sync() override; bool exportToFile(const QUrl &filePath) const override; std::shared_ptr addUnit(std::shared_ptr unit) override; QVector> units() override; void updateFrom(std::shared_ptr course) override; bool isModified() const override; QUrl file() const override; std::shared_ptr self() const override; - Q_INVOKABLE Unit * createUnit(); + Q_INVOKABLE Unit *createUnit(); Q_INVOKABLE std::shared_ptr createPhrase(Unit *unit); Q_SIGNALS: void idChanged(); void foreignIdChanged(); void titleChanged(); void i18nTitleChanged(); void descriptionChanged(); void languageChanged(); private: Q_DISABLE_COPY(EditableCourseResource) /** * Create course resource from file. */ explicit EditableCourseResource(const QUrl &path, IResourceRepository *repository); void setSelf(std::shared_ptr self) override; - mutable bool m_unitsLoaded{ false }; ///< parsing of all units is postponed until needed, this variable indicates if they are read - bool m_modified{ false }; + mutable bool m_unitsLoaded {false}; ///< parsing of all units is postponed until needed, this variable indicates if they are read + bool m_modified {false}; const std::unique_ptr m_course; }; #endif diff --git a/src/core/resources/skeletonresource.cpp b/src/core/resources/skeletonresource.cpp index 63cf7e0..8763704 100644 --- a/src/core/resources/skeletonresource.cpp +++ b/src/core/resources/skeletonresource.cpp @@ -1,375 +1,365 @@ /* * Copyright 2013 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 "skeletonresource.h" -#include "courseparser.h" +#include "artikulate_debug.h" #include "core/language.h" -#include "core/unit.h" -#include "core/phrase.h" -#include "editablecourseresource.h" #include "core/phoneme.h" #include "core/phonemegroup.h" +#include "core/phrase.h" +#include "core/unit.h" +#include "courseparser.h" +#include "editablecourseresource.h" #include -#include #include -#include -#include #include #include -#include "artikulate_debug.h" +#include +#include +#include class SkeletonResourcePrivate { public: SkeletonResourcePrivate(const QUrl &path) : m_path(path) { // load basic information from language file, but does not parse everything QXmlStreamReader xml; QFile file(path.toLocalFile()); if (file.open(QIODevice::ReadOnly)) { xml.setDevice(&file); xml.readNextStartElement(); while (xml.readNext() && !xml.atEnd()) { if (xml.name() == "id") { m_identifier = xml.readElementText(); continue; } if (xml.name() == "title") { m_title = xml.readElementText(); continue; } if (xml.name() == "description") { m_description = xml.readElementText(); continue; } // quit reading when basic elements are read - if (!m_identifier.isEmpty() - && !m_title.isEmpty() - && !m_description.isEmpty() - ) - { + if (!m_identifier.isEmpty() && !m_title.isEmpty() && !m_description.isEmpty()) { break; } } if (xml.hasError()) { qCritical() << "Error occurred when reading Course XML file:" << path.toLocalFile(); } } else { qCCritical(ARTIKULATE_CORE()) << "Could not open course file" << path.toLocalFile(); } xml.clear(); file.close(); m_modified = false; } QVector> units(); std::shared_ptr appendUnit(std::shared_ptr unit); /** * @return the skeleton resource as serialized byte array */ QDomDocument serializedSkeleton(); std::weak_ptr m_self; QUrl m_path; QString m_identifier; QString m_title; QString m_description; - bool m_unitsParsed{ false }; - bool m_modified{ false }; + bool m_unitsParsed {false}; + bool m_modified {false}; protected: QVector> m_units; ///!< the units variable is loaded lazily and shall never be access directly }; QVector> SkeletonResourcePrivate::units() { if (m_unitsParsed) { return m_units; } auto units = CourseParser::parseUnits(m_path); for (auto &unit : units) { Q_ASSERT(m_self.lock() != nullptr); unit->setCourse(m_self.lock()); m_units.append(std::move(unit)); } m_unitsParsed = true; return m_units; } std::shared_ptr SkeletonResourcePrivate::appendUnit(std::shared_ptr unit) { units(); // ensure that units are parsed m_units.append(unit); m_modified = true; Q_ASSERT(m_self.lock() != nullptr); unit->setCourse(m_self.lock()); return m_units.last(); } QDomDocument SkeletonResourcePrivate::serializedSkeleton() { QDomDocument document; // prepare xml header QDomProcessingInstruction header = document.createProcessingInstruction(QStringLiteral("xml"), QStringLiteral("version=\"1.0\"")); document.appendChild(header); // create main element QDomElement root = document.createElement(QStringLiteral("skeleton")); document.appendChild(root); QDomElement idElement = document.createElement(QStringLiteral("id")); QDomElement titleElement = document.createElement(QStringLiteral("title")); QDomElement descriptionElement = document.createElement(QStringLiteral("description")); idElement.appendChild(document.createTextNode(m_identifier)); titleElement.appendChild(document.createTextNode(m_title)); descriptionElement.appendChild(document.createTextNode(m_description)); QDomElement unitListElement = document.createElement(QStringLiteral("units")); // create units for (auto unit : units()) { QDomElement unitElement = document.createElement(QStringLiteral("unit")); QDomElement unitIdElement = document.createElement(QStringLiteral("id")); QDomElement unitTitleElement = document.createElement(QStringLiteral("title")); QDomElement unitPhraseListElement = document.createElement(QStringLiteral("phrases")); unitIdElement.appendChild(document.createTextNode(unit->id())); unitTitleElement.appendChild(document.createTextNode(unit->title())); // construct phrases for (auto &phrase : unit->phrases()) { QDomElement phraseElement = document.createElement(QStringLiteral("phrase")); QDomElement phraseIdElement = document.createElement(QStringLiteral("id")); QDomElement phraseTextElement = document.createElement(QStringLiteral("text")); QDomElement phraseTypeElement = document.createElement(QStringLiteral("type")); phraseIdElement.appendChild(document.createTextNode(phrase->id())); phraseTextElement.appendChild(document.createTextNode(phrase->text())); phraseTypeElement.appendChild(document.createTextNode(phrase->typeString())); phraseElement.appendChild(phraseIdElement); phraseElement.appendChild(phraseTextElement); phraseElement.appendChild(phraseTypeElement); unitPhraseListElement.appendChild(phraseElement); } // construct the unit element unitElement.appendChild(unitIdElement); unitElement.appendChild(unitTitleElement); unitElement.appendChild(unitPhraseListElement); unitListElement.appendChild(unitElement); } root.appendChild(idElement); root.appendChild(titleElement); root.appendChild(descriptionElement); root.appendChild(unitListElement); return document; } std::shared_ptr SkeletonResource::create(const QUrl &path, IResourceRepository *repository) { std::shared_ptr course(new SkeletonResource(path, repository)); course->setSelf(course); return course; } SkeletonResource::SkeletonResource(const QUrl &path, IResourceRepository *repository) : IEditableCourse() , d(new SkeletonResourcePrivate(path)) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); - connect(this, &SkeletonResource::idChanged, this, [=]() { - d->m_modified = true; - }); - connect(this, &SkeletonResource::titleChanged, this, [=]() { - d->m_modified = true; - }); - connect(this, &SkeletonResource::descriptionChanged, this, [=]() { - d->m_modified = true; - }); + connect(this, &SkeletonResource::idChanged, this, [=]() { d->m_modified = true; }); + connect(this, &SkeletonResource::titleChanged, this, [=]() { d->m_modified = true; }); + connect(this, &SkeletonResource::descriptionChanged, this, [=]() { d->m_modified = true; }); Q_UNUSED(repository); } SkeletonResource::~SkeletonResource() = default; void SkeletonResource::setSelf(std::shared_ptr self) { d->m_self = self; } std::shared_ptr SkeletonResource::self() const { return std::static_pointer_cast(d->m_self.lock()); } QString SkeletonResource::id() const { return d->m_identifier; } void SkeletonResource::setId(QString id) { if (d->m_identifier == id) { return; } d->m_identifier = id; emit idChanged(); } QString SkeletonResource::foreignId() const { return id(); } void SkeletonResource::setForeignId(QString id) { Q_UNUSED(id); Q_UNREACHABLE(); } QString SkeletonResource::title() const { return d->m_title; } void SkeletonResource::setTitle(QString title) { if (d->m_title == title) { return; } d->m_title = title; emit titleChanged(); } QString SkeletonResource::i18nTitle() const { // there are no localized titles available return title(); } void SkeletonResource::setI18nTitle(QString title) { Q_UNUSED(title); Q_UNREACHABLE(); } QString SkeletonResource::description() const { return d->m_description; } void SkeletonResource::setDescription(QString description) { if (d->m_description == description) { return; } d->m_description = description; emit descriptionChanged(); } bool SkeletonResource::exportToFile(const QUrl &filePath) const { // write back to file // create directories if necessary - QFileInfo info(filePath.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); + QFileInfo info(filePath.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); if (!info.exists()) { qCDebug(ARTIKULATE_LOG()) << "create xml output file directory, not existing"; QDir dir; - dir.mkpath(filePath.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); + dir.mkpath(filePath.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); } - //TODO port to atomic file swap + // TODO port to atomic file swap QFile file(filePath.toLocalFile()); if (!file.open(QIODevice::WriteOnly)) { qCWarning(ARTIKULATE_LOG()) << "Unable to open file " << filePath << " in write mode, aborting."; return false; } file.write(d->serializedSkeleton().toByteArray()); return true; } std::shared_ptr SkeletonResource::addUnit(std::shared_ptr unit) { std::shared_ptr storedUnit(std::move(unit)); emit unitAboutToBeAdded(storedUnit, d->units().count() - 1); d->appendUnit(storedUnit); emit unitAdded(); return storedUnit; } bool SkeletonResource::sync() { if (!d->m_modified) { qCDebug(ARTIKULATE_LOG()) << "Aborting sync, skeleton was not modified."; return false; } bool ok = exportToFile(file()); if (ok) { d->m_modified = false; } return ok; } void SkeletonResource::updateFrom(std::shared_ptr) { // not supported } bool SkeletonResource::isModified() const { return d->m_modified; } std::shared_ptr SkeletonResource::language() const { // skeleton must not have a dedicated language return std::shared_ptr(); } QString SkeletonResource::languageTitle() const { return QString(); } void SkeletonResource::setLanguage(std::shared_ptr language) { Q_UNUSED(language); Q_UNREACHABLE(); } QVector> SkeletonResource::units() { return d->units(); } QUrl SkeletonResource::file() const { return d->m_path; } diff --git a/src/core/trainingaction.cpp b/src/core/trainingaction.cpp index ecae445..e82e622 100644 --- a/src/core/trainingaction.cpp +++ b/src/core/trainingaction.cpp @@ -1,110 +1,110 @@ /* * 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 "trainingactionicon.h" #include "trainingsession.h" TrainingAction::TrainingAction(QObject *parent) : QObject(parent) , m_text(QString()) - , m_icon(new TrainingActionIcon(this, QString())) //TODO "rating-unrated" vs. "rating" + , 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" + , m_icon(new TrainingActionIcon(this, QString())) // TODO "rating-unrated" vs. "rating" { } -TrainingAction::TrainingAction(std::shared_ptr phrase, ISessionActions *session, QObject* parent) +TrainingAction::TrainingAction(std::shared_ptr phrase, ISessionActions *session, QObject *parent) : QObject(parent) , m_icon(new TrainingActionIcon(this, QString())) , m_phrase(phrase) , m_session(session) { if (m_phrase) { m_text = phrase->text(); } } -void TrainingAction::appendChild(QObject* child) +void TrainingAction::appendChild(QObject *child) { m_actions.append(child); emit actionsChanged(); } bool TrainingAction::hasChildren() const { return m_actions.count() > 0; } void TrainingAction::trigger() { if (m_phrase && m_session) { m_session->setActivePhrase(m_phrase.get()); } } bool TrainingAction::enabled() const { return m_enabled; } void TrainingAction::setEnabled(bool enabled) { if (enabled == m_enabled) { return; } m_enabled = enabled; emit enabledChanged(m_enabled); } bool TrainingAction::checked() const { return m_checked; } void TrainingAction::setChecked(bool checked) { if (checked == m_checked) { return; } m_checked = checked; emit checkedChanged(m_checked); } -QObject * TrainingAction::icon() const +QObject *TrainingAction::icon() const { return m_icon; } -IPhrase * TrainingAction::phrase() const +IPhrase *TrainingAction::phrase() const { return m_phrase.get(); } QList TrainingAction::actions() const { return m_actions; } diff --git a/src/core/trainingaction.h b/src/core/trainingaction.h index 0fbc7f7..44d7ea0 100644 --- a/src/core/trainingaction.h +++ b/src/core/trainingaction.h @@ -1,79 +1,79 @@ /* * 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 "iphrase.h" +#include "trainingactionicon.h" #include "trainingsession.h" -#include #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(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 READ checked NOTIFY checkedChanged) Q_PROPERTY(QString tooltip MEMBER m_tooltip CONSTANT) - Q_PROPERTY(QList children READ actions NOTIFY actionsChanged) + Q_PROPERTY(QList children READ actions NOTIFY actionsChanged) Q_PROPERTY(bool checkable MEMBER m_checkable CONSTANT) public: TrainingAction(QObject *parent = nullptr); TrainingAction(const QString &text, QObject *parent = nullptr); TrainingAction(std::shared_ptr phrase, ISessionActions *session, QObject *parent = nullptr); void appendChild(QObject *child); bool hasChildren() const; Q_INVOKABLE void trigger(); bool enabled() const; void setEnabled(bool enabled); void setChecked(bool checked); bool checked() const; - QObject * icon() const; - IPhrase * phrase() const; - QList actions() const; + QObject *icon() const; + IPhrase *phrase() const; + QList actions() const; Q_SIGNALS: void changed(); void actionsChanged(); void enabledChanged(bool enabled); void checkedChanged(bool checked); 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_actions; + 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_actions; std::shared_ptr m_phrase; - ISessionActions * m_session{nullptr}; + ISessionActions *m_session {nullptr}; }; #endif diff --git a/src/core/trainingactionicon.h b/src/core/trainingactionicon.h index 9aef8fc..f104a1f 100644 --- a/src/core/trainingactionicon.h +++ b/src/core/trainingactionicon.h @@ -1,48 +1,48 @@ /* * Copyright 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 TRAININGACTIONICON_H #define TRAININGACTIONICON_H #include "artikulatecore_export.h" -#include #include +#include class ARTIKULATECORE_EXPORT TrainingActionIcon : public QObject { Q_OBJECT Q_PROPERTY(QString name MEMBER m_name CONSTANT) Q_PROPERTY(QString source MEMBER m_source CONSTANT) Q_PROPERTY(int width MEMBER m_width) Q_PROPERTY(int height MEMBER m_height) Q_PROPERTY(QColor color MEMBER m_color CONSTANT) public: explicit TrainingActionIcon(QObject *parent, const QString &name = QString(), const QString &source = QString(), int width = 60, int height = 60, const QColor &color = QColor(0, 0, 0)); private: - QString m_name{QString()}; - QString m_source{QString()}; - int m_width{60}; - int m_height{60}; + QString m_name {QString()}; + QString m_source {QString()}; + int m_width {60}; + int m_height {60}; QColor m_color; }; #endif diff --git a/src/core/trainingsession.cpp b/src/core/trainingsession.cpp index 46760cc..7bfccfd 100644 --- a/src/core/trainingsession.cpp +++ b/src/core/trainingsession.cpp @@ -1,310 +1,298 @@ /* * 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 "artikulate_debug.h" #include "core/icourse.h" -#include "core/unit.h" +#include "core/language.h" #include "core/phrase.h" -#include "profilemanager.h" +#include "core/unit.h" #include "learner.h" +#include "profilemanager.h" #include "trainingaction.h" -#include "artikulate_debug.h" TrainingSession::TrainingSession(LearnerProfile::ProfileManager *manager, QObject *parent) : ISessionActions(parent) , m_profileManager(manager) , m_course(nullptr) { Q_ASSERT(m_profileManager != nullptr); } -ICourse * TrainingSession::course() const +ICourse *TrainingSession::course() const { return m_course; } void TrainingSession::setCourse(ICourse *course) { if (!course) { updateTrainingActions(); return; } if (m_course == course) { return; } m_course = course; if (m_course && m_course->units().count() > 0) { setUnit(m_course->units().constFirst().get()); } // lazy loading of training data - LearnerProfile::LearningGoal * goal = m_profileManager->goal( - LearnerProfile::LearningGoal::Language, m_course->id()); + 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() - ); + 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() - ); + auto data = m_profileManager->progressValues(m_profileManager->activeProfile(), goal, m_course->id()); const auto unitList = m_course->units(); for (auto unit : qAsConst(unitList)) { const auto phrases = unit->phrases(); for (auto &phrase : phrases) { auto iter = data.find(phrase->id()); if (iter != data.end()) { -// phrase->setProgress(iter.value()); //FIXME add a decorator? + // phrase->setProgress(iter.value()); //FIXME add a decorator? } } } updateTrainingActions(); emit courseChanged(); } -IUnit * TrainingSession::activeUnit() const +IUnit *TrainingSession::activeUnit() const { if (auto phrase = activePhrase()) { return phrase->unit().get(); } return nullptr; } void TrainingSession::setUnit(IUnit *unit) { // checking phrases in increasing order ensures that always the first phrase is selected for (int i = 0; i < m_actions.count(); ++i) { for (int j = 0; j < m_actions.at(i)->actions().count(); ++j) { - const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); + const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); if (unit == testPhrase->unit().get()) { if (auto action = activeAction()) { action->setChecked(false); } m_indexUnit = i; m_indexPhrase = j; if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); return; } } } } -TrainingAction * TrainingSession::activeAction() const +TrainingAction *TrainingSession::activeAction() const { if (m_indexUnit < 0 || m_indexPhrase < 0) { return nullptr; } - return qobject_cast(m_actions.at(m_indexUnit)->actions().at(m_indexPhrase)); + return qobject_cast(m_actions.at(m_indexUnit)->actions().at(m_indexPhrase)); } -IPhrase * TrainingSession::activePhrase() const +IPhrase *TrainingSession::activePhrase() const { if (const auto action = activeAction()) { return action->phrase(); } return nullptr; } void TrainingSession::setActivePhrase(IPhrase *phrase) { for (int i = 0; i < m_actions.count(); ++i) { for (int j = 0; j < m_actions.at(i)->actions().count(); ++j) { - const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); + const auto testPhrase = qobject_cast(m_actions.at(i)->actions().at(j))->phrase(); if (phrase == testPhrase) { if (auto action = activeAction()) { action->setChecked(false); } m_indexUnit = i; m_indexPhrase = j; if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); return; } } } } void TrainingSession::accept() { Q_ASSERT(m_indexUnit >= 0); Q_ASSERT(m_indexPhrase >= 0); if (m_indexUnit < 0 || m_indexPhrase < 0) { return; } auto phrase = activePhrase(); // possibly update goals of learner updateGoal(); -// phrase->updateProgress(Phrase::Progress::Done); //FIXME + // phrase->updateProgress(Phrase::Progress::Done); //FIXME // store training activity - LearnerProfile::LearningGoal * goal = m_profileManager->goal( - LearnerProfile::LearningGoal::Language, m_course->language()->id()); -// m_profileManager->recordProgress(m_profileManager->activeProfile(), //FIXME -// goal, -// m_course->id(), -// phrase->id(), -// static_cast(LearnerProfile::ProfileManager::Skip), -// phrase->progress() -// ); + LearnerProfile::LearningGoal *goal = m_profileManager->goal(LearnerProfile::LearningGoal::Language, m_course->language()->id()); + // m_profileManager->recordProgress(m_profileManager->activeProfile(), //FIXME + // goal, + // m_course->id(), + // phrase->id(), + // static_cast(LearnerProfile::ProfileManager::Skip), + // phrase->progress() + // ); selectNextPhrase(); } void TrainingSession::skip() { Q_ASSERT(m_indexUnit >= 0); Q_ASSERT(m_indexPhrase >= 0); if (m_indexUnit < 0 || m_indexPhrase < 0) { return; } // possibly update goals of learner updateGoal(); auto phrase = activePhrase(); -// phrase->updateProgress(Phrase::Progress::Skip); //FIXME + // phrase->updateProgress(Phrase::Progress::Skip); //FIXME // 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(), -// phrase->id(), -// static_cast(LearnerProfile::ProfileManager::Skip), -// phrase->progress() -// ); // FIXME + LearnerProfile::LearningGoal *goal = m_profileManager->goal(LearnerProfile::LearningGoal::Language, m_course->language()->id()); + // m_profileManager->recordProgress(m_profileManager->activeProfile(), + // goal, + // m_course->id(), + // phrase->id(), + // static_cast(LearnerProfile::ProfileManager::Skip), + // phrase->progress() + // ); // FIXME selectNextPhrase(); } void TrainingSession::selectNextPhrase() { if (auto action = activeAction()) { action->setChecked(false); } // try to find next phrase, otherwise return completed if (m_indexPhrase >= m_actions.at(m_indexUnit)->actions().count() - 1) { qDebug() << "switching to next unit"; if (m_indexUnit >= m_actions.count() - 1) { emit completed(); } else { ++m_indexUnit; m_indexPhrase = 0; } } else { ++m_indexPhrase; } if (auto action = activeAction()) { action->setChecked(true); } emit phraseChanged(); } bool TrainingSession::hasPrevious() const { return m_indexUnit > 0 || m_indexPhrase > 0; } bool TrainingSession::hasNext() const { if (m_indexUnit < m_actions.count() - 1) { return true; } if (m_actions.constLast()) { if (m_indexPhrase < m_actions.constLast()->actions().count() - 1) { return true; } } return false; } 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()); + LearnerProfile::LearningGoal *goal = m_profileManager->goal(LearnerProfile::LearningGoal::Language, m_course->language()->id()); learner->addGoal(goal); learner->setActiveGoal(goal); } QVector TrainingSession::trainingActions() const { return m_actions; } void TrainingSession::updateTrainingActions() { for (const auto &action : qAsConst(m_actions)) { action->deleteLater(); } m_actions.clear(); if (!m_course) { m_indexUnit = -1; m_indexPhrase = -1; return; } const auto unitList = m_course->units(); for (const auto &unit : qAsConst(unitList)) { auto action = new TrainingAction(unit->title(), this); const auto phraseList = unit->phrases(); for (const auto &phrase : qAsConst(phraseList)) { if (phrase->sound().isEmpty()) { continue; } action->appendChild(new TrainingAction(phrase, this, unit.get())); } if (action->hasChildren()) { m_actions.append(action); } else { action->deleteLater(); } } // update indices m_indexUnit = -1; m_indexPhrase = -1; if (m_course->units().count() > 0) { m_indexUnit = 0; if (m_course->units().constFirst()->phrases().count() > 0) { m_indexPhrase = 0; } } } - diff --git a/src/core/trainingsession.h b/src/core/trainingsession.h index f953df3..43b14d8 100644 --- a/src/core/trainingsession.h +++ b/src/core/trainingsession.h @@ -1,94 +1,95 @@ /* * 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 "isessionactions.h" #include "phrase.h" #include class Language; class ICourse; class Unit; class TrainingAction; -namespace LearnerProfile { - class ProfileManager; +namespace LearnerProfile +{ +class ProfileManager; } /** * \class TrainingSession */ class ARTIKULATECORE_EXPORT TrainingSession : public ISessionActions { Q_OBJECT Q_INTERFACES(ISessionActions) Q_PROPERTY(ICourse *course READ course WRITE setCourse NOTIFY courseChanged) Q_PROPERTY(IUnit *unit READ activeUnit WRITE setUnit NOTIFY phraseChanged) Q_PROPERTY(IPhrase *phrase READ activePhrase WRITE setActivePhrase NOTIFY phraseChanged) Q_PROPERTY(bool hasNext READ hasNext NOTIFY phraseChanged) public: explicit TrainingSession(LearnerProfile::ProfileManager *manager, QObject *parent = nullptr); - ICourse * course() const; + ICourse *course() const; void setCourse(ICourse *course); - IUnit * activeUnit() const; + IUnit *activeUnit() const; void setUnit(IUnit *unit); - TrainingAction * activeAction() const override; - IPhrase * activePhrase() const; + TrainingAction *activeAction() const override; + IPhrase *activePhrase() const; void setActivePhrase(IPhrase *phrase) override; bool hasPrevious() const; bool hasNext() const; Q_INVOKABLE void accept(); Q_INVOKABLE void skip(); /** * @brief Return tree of training actions * * The return actions form a 2-level hierarchy: * - the first level are all units * - the unit actions may contain sub-actions, which are the phrases * * @note phrases without sound file paths are skipped when generating actions */ QVector trainingActions() const override; Q_SIGNALS: /** * @brief Emitted when last phrase of session is skipped or marked as completed. */ void completed(); private: Q_DISABLE_COPY(TrainingSession) void updateTrainingActions(); void selectNextPhrase(); void updateGoal(); LearnerProfile::ProfileManager *m_profileManager; ICourse *m_course; - QVector m_actions; + QVector m_actions; - int m_indexUnit{-1}; - int m_indexPhrase{-1}; + int m_indexUnit {-1}; + int m_indexPhrase {-1}; }; #endif diff --git a/src/core/unit.cpp b/src/core/unit.cpp index 3fed3f5..2d44e33 100644 --- a/src/core/unit.cpp +++ b/src/core/unit.cpp @@ -1,171 +1,171 @@ /* * Copyright 2013-2015 Andreas Cord-Landwehr * Copyright 2013 Oindrila Gupta * * 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 "unit.h" #include "phrase.h" #include +#include #include #include -#include #include "artikulate_debug.h" #include #include Unit::Unit(QObject *parent) : IEditableUnit(parent) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } Unit::~Unit() = default; std::shared_ptr Unit::create() { std::shared_ptr unit(new Unit); unit->setSelf(unit); return unit; } void Unit::setSelf(std::shared_ptr self) { m_self = self; } std::shared_ptr Unit::self() const { - return m_self.lock(); + return m_self.lock(); } QString Unit::id() const { return m_id; } void Unit::setId(const QString &id) { if (id != m_id) { m_id = id; emit idChanged(); emit modified(); } } QString Unit::foreignId() const { return m_foreignId; } void Unit::setForeignId(const QString &id) { m_foreignId = id; } std::shared_ptr Unit::course() const { return m_course.lock(); } void Unit::setCourse(std::shared_ptr course) { if (course == m_course.lock()) { return; } m_course = course; emit courseChanged(); } QString Unit::title() const { return m_title; } void Unit::setTitle(const QString &title) { if (QString::compare(title, m_title) != 0) { m_title = title; emit titleChanged(); emit modified(); } } QVector> Unit::phrases() const { return m_phrases; } void Unit::addPhrase(std::shared_ptr phrase) { auto iter = m_phrases.constBegin(); while (iter != m_phrases.constEnd()) { if (phrase->id() == (*iter)->id()) { qCWarning(ARTIKULATE_LOG()) << "Phrase is already contained in this unit, aborting"; return; } ++iter; } phrase->setUnit(m_self.lock()); emit phraseAboutToBeAdded(phrase, m_phrases.length()); m_phrases.append(phrase); emit phraseAdded(phrase); connect(phrase.get(), &Phrase::modified, this, &Unit::modified); emit modified(); } QList Unit::excludedSkeletonPhraseList() const { QList excludedPhraseList; -//TODO this should not be handled on unit level -// for (auto phrase : m_phrases) { -// if (phrase->isExcluded() == true) { -// excludedPhraseList.append(phrase); -// } -// } + // TODO this should not be handled on unit level + // for (auto phrase : m_phrases) { + // if (phrase->isExcluded() == true) { + // excludedPhraseList.append(phrase); + // } + // } return excludedPhraseList; } void Unit::excludeSkeletonPhrase(const QString &phraseId) { -// for (auto phrase : m_phrases) { -// if (phrase->id() == phraseId) { -// phrase->setExcluded(true); -// emit modified(); -// return; -// } -// } + // for (auto phrase : m_phrases) { + // if (phrase->id() == phraseId) { + // phrase->setExcluded(true); + // emit modified(); + // return; + // } + // } qCWarning(ARTIKULATE_LOG) << "Could not exclude phrase with ID " << phraseId << ", no phrase with this ID."; } void Unit::includeSkeletonPhrase(const QString &phraseId) { -// for (auto phrase : m_phrases) { -// if (phrase->id() == phraseId) { -// phrase->setExcluded(false); -// emit modified(); -// return; -// } -// } + // for (auto phrase : m_phrases) { + // if (phrase->id() == phraseId) { + // phrase->setExcluded(false); + // emit modified(); + // return; + // } + // } qCWarning(ARTIKULATE_LOG) << "Could not include phrase with ID " << phraseId << ", no phrase with this ID."; } diff --git a/src/core/unit.h b/src/core/unit.h index fef8019..96c13a6 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -1,82 +1,82 @@ /* * Copyright 2013 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 UNIT_H #define UNIT_H #include "artikulatecore_export.h" #include "ieditableunit.h" -#include #include -#include #include +#include +#include class QString; class Phrase; class IPhrase; class ICourse; class ARTIKULATECORE_EXPORT Unit : public IEditableUnit { Q_OBJECT Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged) Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) public: static std::shared_ptr create(); ~Unit() override; QString id() const override; void setId(const QString &id) override; QString foreignId() const override; void setForeignId(const QString &id) override; std::shared_ptr course() const override; void setCourse(std::shared_ptr course) override; QString title() const override; void setTitle(const QString &title) override; QVector> phrases() const override; void addPhrase(std::shared_ptr phrase) override; QList excludedSkeletonPhraseList() const; std::shared_ptr self() const override; /** * Removes phrase with ID \p phraseId from unit and adds ID to set * of excluded IDs. * * \param phraseId is the UID of the to be excluded phrase */ Q_INVOKABLE void excludeSkeletonPhrase(const QString &phraseId); Q_INVOKABLE void includeSkeletonPhrase(const QString &phraseId); protected: explicit Unit(QObject *parent = nullptr); private: void setSelf(std::shared_ptr self) override; Q_DISABLE_COPY(Unit) std::weak_ptr m_self; QString m_id; QString m_foreignId; std::weak_ptr m_course; QString m_title; QVector> m_phrases; }; #endif // UNIT_H diff --git a/src/main.cpp b/src/main.cpp index ded6ab1..ad3d368 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,72 +1,63 @@ /* * Copyright 2013-2017 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 "mainwindow.h" #include "application.h" +#include "mainwindow.h" #include "version.h" +#include "artikulate_debug.h" #include #include #include -#include "artikulate_debug.h" int main(int argc, char **argv) { Application app(argc, argv); KLocalizedString::setApplicationDomain("artikulate"); ResourceRepository repository; repository.reloadCourses(); app.installResourceRepository(&repository); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("artikulate"))); KAboutData aboutData(QStringLiteral("artikulate"), i18nc("@title Displayed program name", "Artikulate"), ARTIKULATE_VERSION_STRING, i18nc("@title KAboutData: short program description", "Artikulate Pronunciation Trainer"), KAboutLicense::GPL_V2, i18nc("@info:credit", "(c) 2013-2019 The Artikulate Developers"), - i18nc("@title Short program description", "Train your pronunciation in a foreign language.") - ); + i18nc("@title Short program description", "Train your pronunciation in a foreign language.")); aboutData.setProgramLogo(app.windowIcon()); - aboutData.addAuthor(i18nc("@info:credit Developer name", "Andreas Cord-Landwehr"), - i18nc("@info:credit Role", "Original Author"), - QStringLiteral("cordlandwehr@kde.org")); + aboutData.addAuthor(i18nc("@info:credit Developer name", "Andreas Cord-Landwehr"), i18nc("@info:credit Role", "Original Author"), QStringLiteral("cordlandwehr@kde.org")); - aboutData.addAuthor(i18nc("@info:credit Developer name", "Samikshan Bairagya"), - i18nc("@info:credit Role", "Developer"), - QStringLiteral("samikshan@gmail.com")); + aboutData.addAuthor(i18nc("@info:credit Developer name", "Samikshan Bairagya"), i18nc("@info:credit Role", "Developer"), QStringLiteral("samikshan@gmail.com")); - aboutData.addAuthor(i18nc("@info:credit Developer name", "Oindrila Gupta"), - i18nc("@info:credit Role", "Developer and Course Data"), - QStringLiteral("edu@kde.org")); + aboutData.addAuthor(i18nc("@info:credit Developer name", "Oindrila Gupta"), i18nc("@info:credit Role", "Developer and Course Data"), QStringLiteral("edu@kde.org")); - aboutData.addAuthor(i18nc("@info:credit Developer name", "Magdalena Konkiewicz"), - i18nc("@info:credit Role", "Developer and Course Data"), - QStringLiteral("edu@kde.org")); + aboutData.addAuthor(i18nc("@info:credit Developer name", "Magdalena Konkiewicz"), i18nc("@info:credit Role", "Developer and Course Data"), QStringLiteral("edu@kde.org")); aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); KAboutData::setApplicationData(aboutData); KCrash::initialize(); new MainWindow(); return app.exec(); } diff --git a/src/main_editor.cpp b/src/main_editor.cpp index 04932f2..f9b0be4 100644 --- a/src/main_editor.cpp +++ b/src/main_editor.cpp @@ -1,58 +1,55 @@ /* * Copyright 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 "version.h" #include "application.h" #include "core/contributorrepository.h" #include "mainwindow_editor.h" +#include "version.h" +#include "artikulate_debug.h" #include #include #include -#include "artikulate_debug.h" int main(int argc, char **argv) { Application app(argc, argv); KLocalizedString::setApplicationDomain("artikulate"); ContributorRepository repository; repository.reloadCourses(); app.installResourceRepository(&repository); KAboutData aboutData(QStringLiteral("artikulate_editor"), ki18nc("@title Displayed program name", "Artikulate Editor").toString(), ARTIKULATE_VERSION_STRING, ki18nc("@title KAboutData: short program description", "Artikulate Course Editor").toString(), KAboutLicense::GPL_V2, ki18nc("@info:credit", "(c) 2013-2019 The Artikulate Developers").toString(), - ki18nc("@title Short program description", "Edit Artikulate course files.").toString() - ); + ki18nc("@title Short program description", "Edit Artikulate course files.").toString()); - aboutData.addAuthor(ki18nc("@info:credit Developer name", "Andreas Cord-Landwehr").toString(), - ki18nc("@info:credit Role", "Original Author").toString(), - QStringLiteral("cordlandwehr@kde.org")); + aboutData.addAuthor(ki18nc("@info:credit Developer name", "Andreas Cord-Landwehr").toString(), ki18nc("@info:credit Role", "Original Author").toString(), QStringLiteral("cordlandwehr@kde.org")); KAboutData::setApplicationData(aboutData); KCrash::initialize(); MainWindowEditor *mainWindow = new MainWindowEditor(&repository); return app.exec(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 069509d..7b29d7e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,186 +1,184 @@ /* * 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 "mainwindow.h" -#include "ui/sounddevicedialogpage.h" -#include "core/resourcerepository.h" -#include "core/trainingsession.h" +#include "application.h" +#include "artikulate_debug.h" #include "core/editorsession.h" +#include "core/resourcerepository.h" #include "core/resources/courseresource.h" -#include "application.h" -#include "models/languagemodel.h" -#include "settings.h" -#include "liblearnerprofile/src/profilemanager.h" +#include "core/trainingsession.h" #include "liblearnerprofile/src/learner.h" +#include "liblearnerprofile/src/profilemanager.h" #include "libsound/src/outputdevicecontroller.h" -#include "artikulate_debug.h" +#include "models/languagemodel.h" +#include "settings.h" +#include "ui/sounddevicedialogpage.h" +#include #include #include -#include #include -#include #include +#include #include #include #include #include #include #include #include using namespace LearnerProfile; MainWindow::MainWindow() : m_actionCollection(new KActionCollection(this, QStringLiteral("artikulate"))) , m_profileManager(new LearnerProfile::ProfileManager(this)) , m_trainingSession(new TrainingSession(m_profileManager, this)) { rootContext()->setContextObject(new KLocalizedContext(this)); // load saved sound settings OutputDeviceController::self().setVolume(Settings::audioOutputVolume()); // create menu setupActions(); // set view rootContext()->setContextProperty(QStringLiteral("g_trainingSession"), m_trainingSession); rootContext()->setContextProperty(QStringLiteral("g_profileManager"), m_profileManager); rootContext()->setContextProperty(QStringLiteral("g_artikulateAboutData"), QVariant::fromValue(KAboutData::applicationData())); // set starting screen load(QUrl(QStringLiteral("qrc:/artikulate/qml/Main.qml"))); // create training profile if none exists: if (!m_profileManager->activeProfile()) { m_profileManager->addProfile(i18n("Unnamed Identity")); } // connect to QML signals; - connect(rootObjects().constFirst(), SIGNAL(ghnsCourseDataStatusChanged()), - this, SLOT(updateCourseResources())); - connect(rootObjects().constFirst(), SIGNAL(triggerAction(QString)), - this, SLOT(triggerAction(QString))); + connect(rootObjects().constFirst(), SIGNAL(ghnsCourseDataStatusChanged()), this, SLOT(updateCourseResources())); + connect(rootObjects().constFirst(), SIGNAL(triggerAction(QString)), this, SLOT(triggerAction(QString))); // set font for the phrase in trainer to default from kcfg file - QObject *phraseText = rootObjects().constFirst()->findChild(QStringLiteral("phraseText")); + QObject *phraseText = rootObjects().constFirst()->findChild(QStringLiteral("phraseText")); if (phraseText) { phraseText->setProperty("font", Settings::trainingPhraseFont()); } } MainWindow::~MainWindow() { // save current settings for case of closing Settings::self()->save(); m_profileManager->sync(); } -KActionCollection * MainWindow::actionCollection() +KActionCollection *MainWindow::actionCollection() { return m_actionCollection; } void MainWindow::setupActions() { QAction *settingsAction = new QAction(i18nc("@item:inmenu", "Configure Artikulate"), this); connect(settingsAction, &QAction::triggered, this, &MainWindow::showSettingsDialog); actionCollection()->addAction(QStringLiteral("settings"), settingsAction); settingsAction->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); QAction *configLearnerProfileAction = new QAction(i18nc("@item:inmenu", "Learner Profile"), this); connect(configLearnerProfileAction, &QAction::triggered, this, &MainWindow::configLearnerProfile); actionCollection()->addAction(QStringLiteral("config_learner_profile"), configLearnerProfileAction); configLearnerProfileAction->setIcon(QIcon::fromTheme(QStringLiteral("user-identity"))); KStandardAction::quit(qApp, SLOT(quit()), actionCollection()); } void MainWindow::showSettingsDialog() { if (KConfigDialog::showDialog(QStringLiteral("settings"))) { return; } QPointer dialog = new KConfigDialog(nullptr, QStringLiteral("settings"), Settings::self()); SoundDeviceDialogPage *soundDialog = new SoundDeviceDialogPage(); soundDialog->loadSettings(); dialog->addPage(soundDialog, i18nc("@item:inmenu", "Sound Devices"), QStringLiteral("audio-headset"), i18nc("@title:tab", "Sound Device Settings"), true); connect(dialog.data(), &QDialog::accepted, soundDialog, &SoundDeviceDialogPage::saveSettings); connect(dialog.data(), &QDialog::accepted, this, &MainWindow::updateTrainingPhraseFont); connect(dialog.data(), &QDialog::accepted, this, &MainWindow::updateKcfgUseContributorResources); connect(dialog.data(), &QDialog::finished, soundDialog, &SoundDeviceDialogPage::stopPlaying); connect(dialog.data(), &QDialog::finished, soundDialog, &SoundDeviceDialogPage::stopRecord); dialog->exec(); } void MainWindow::updateCourseResources() { artikulateApp->resourceRepository()->reloadCourses(); } void MainWindow::updateTrainingPhraseFont() { - QObject *phraseText = rootObjects().constFirst()->findChild(QStringLiteral("phraseText")); + QObject *phraseText = rootObjects().constFirst()->findChild(QStringLiteral("phraseText")); if (!phraseText) { qCDebug(ARTIKULATE_LOG) << "no phraseText context object found, aborting"; return; } phraseText->setProperty("font", Settings::trainingPhraseFont()); } void MainWindow::updateKcfgUseContributorResources() { rootContext()->setContextProperty(QStringLiteral("kcfg_UseContributorResources"), Settings::useCourseRepository()); } void MainWindow::configLearnerProfile() { - qCritical() << "Not implemented"; //FIXME + qCritical() << "Not implemented"; // FIXME } void MainWindow::triggerAction(const QString &actionName) { - QAction * action = actionCollection()->action(actionName); + QAction *action = actionCollection()->action(actionName); if (action) { action->trigger(); } else { qCritical() << "Action is not registered:" << actionName; } } void MainWindow::switchMenuBarVisibility() { Settings::setShowMenuBar(!Settings::showMenuBar()); rootContext()->setContextProperty(QStringLiteral("kcfg_ShowMenuBar"), Settings::showMenuBar()); } bool MainWindow::queryClose() { Settings::self()->save(); // FIXME make sure all learner data is written to database return true; } diff --git a/src/mainwindow.h b/src/mainwindow.h index 47dfe47..858bce2 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,72 +1,73 @@ /* * 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 MAINWINDOW_H #define MAINWINDOW_H -#include -#include #include "core/resourcerepository.h" +#include +#include class TrainingSession; class KHelpMenu; -namespace LearnerProfile { - class ProfileManager; +namespace LearnerProfile +{ +class ProfileManager; } class MainWindow : public QQmlApplicationEngine { Q_OBJECT public: /** * Default Constructor */ MainWindow(); /** * Default Destructor */ ~MainWindow() override; - const IResourceRepository * resourceRepository() const; + const IResourceRepository *resourceRepository() const; - KActionCollection * actionCollection(); + KActionCollection *actionCollection(); void setupActions(); bool queryClose(); public Q_SLOTS: void showSettingsDialog(); void updateCourseResources(); void updateTrainingPhraseFont(); void updateKcfgUseContributorResources(); void configLearnerProfile(); void switchMenuBarVisibility(); void triggerAction(const QString &); private: KActionCollection *m_actionCollection; KHelpMenu *m_helpMenu; LearnerProfile::ProfileManager *m_profileManager; TrainingSession *m_trainingSession; }; #endif diff --git a/src/mainwindow_editor.cpp b/src/mainwindow_editor.cpp index e2455e4..ae876fd 100644 --- a/src/mainwindow_editor.cpp +++ b/src/mainwindow_editor.cpp @@ -1,156 +1,156 @@ /* * 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 "mainwindow_editor.h" #include "application.h" -#include "ui/sounddevicedialogpage.h" -#include "ui/exportghnsdialog.h" +#include "artikulate_debug.h" #include "core/editorsession.h" #include "core/resources/courseresource.h" +#include "libsound/src/outputdevicecontroller.h" #include "models/languagemodel.h" #include "settings.h" -#include "libsound/src/outputdevicecontroller.h" -#include "artikulate_debug.h" +#include "ui/exportghnsdialog.h" +#include "ui/sounddevicedialogpage.h" +#include #include #include -#include #include +#include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace LearnerProfile; MainWindowEditor::MainWindowEditor(ContributorRepository *repository) : m_repository(repository) , m_editorSession(new EditorSession()) { rootContext()->setContextObject(new KLocalizedContext(this)); rootContext()->setContextProperty(QStringLiteral("g_repository"), m_repository); rootContext()->setContextProperty(QStringLiteral("g_editorSession"), m_editorSession); rootContext()->setContextProperty(QStringLiteral("g_artikulateAboutData"), QVariant::fromValue(KAboutData::applicationData())); m_repository->setStorageLocation(QUrl::fromLocalFile(Settings::courseRepositoryPath())); m_editorSession->setRepository(m_repository); // load saved sound settings OutputDeviceController::self().setVolume(Settings::audioOutputVolume()); m_repository->reloadCourses(); // create menu setupActions(); // set starting screen load(QUrl(QStringLiteral("qrc:/artikulate/qml/Editor.qml"))); -// QAction *newAct = KStandardAction::save(this, SLOT(save()), actionCollection()); -// actionCollection()->addAction(QStringLiteral("save"), newAct); + // QAction *newAct = KStandardAction::save(this, SLOT(save()), actionCollection()); + // actionCollection()->addAction(QStringLiteral("save"), newAct); } MainWindowEditor::~MainWindowEditor() { // save current settings for case of closing Settings::self()->save(); } -ContributorRepository * MainWindowEditor::resourceRepository() const +ContributorRepository *MainWindowEditor::resourceRepository() const { return m_repository; } void MainWindowEditor::setupActions() { -// QAction *settingsAction = new QAction(i18nc("@item:inmenu", "Configure Artikulate"), this); -// connect(settingsAction, &QAction::triggered, this, &MainWindowEditor::showSettingsDialog); -// actionCollection()->addAction(QStringLiteral("settings"), settingsAction); -// settingsAction->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); - -// QAction *exportAction = new QAction(i18nc("@item:inmenu", "Export GHNS Files"), this); -// connect(exportAction, &QAction::triggered, this, [=]() { -// QPointer dialog = new ExportGhnsDialog(m_repository); -// dialog->exec(); -// }); -// actionCollection()->addAction(QStringLiteral("export_ghns"), exportAction); -// exportAction->setIcon(QIcon::fromTheme(QStringLiteral("document-export"))); - -// KStandardAction::quit(this, SLOT(quit()), actionCollection()); + // QAction *settingsAction = new QAction(i18nc("@item:inmenu", "Configure Artikulate"), this); + // connect(settingsAction, &QAction::triggered, this, &MainWindowEditor::showSettingsDialog); + // actionCollection()->addAction(QStringLiteral("settings"), settingsAction); + // settingsAction->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); + + // QAction *exportAction = new QAction(i18nc("@item:inmenu", "Export GHNS Files"), this); + // connect(exportAction, &QAction::triggered, this, [=]() { + // QPointer dialog = new ExportGhnsDialog(m_repository); + // dialog->exec(); + // }); + // actionCollection()->addAction(QStringLiteral("export_ghns"), exportAction); + // exportAction->setIcon(QIcon::fromTheme(QStringLiteral("document-export"))); + + // KStandardAction::quit(this, SLOT(quit()), actionCollection()); } void MainWindowEditor::showSettingsDialog() { if (KConfigDialog::showDialog(QStringLiteral("settings"))) { return; } QPointer dialog = new KConfigDialog(nullptr, QStringLiteral("settings"), Settings::self()); SoundDeviceDialogPage *soundDialog = new SoundDeviceDialogPage(); soundDialog->loadSettings(); dialog->addPage(soundDialog, i18nc("@item:inmenu", "Sound Devices"), QStringLiteral("audio-headset"), i18nc("@title:tab", "Sound Device Settings"), true); connect(dialog.data(), &QDialog::accepted, soundDialog, &SoundDeviceDialogPage::saveSettings); dialog->exec(); } void MainWindowEditor::save() { m_repository->sync(); } void MainWindowEditor::quit() { -// if (queryClose()) { -// qApp->quit(); -// } + // if (queryClose()) { + // qApp->quit(); + // } } -//bool MainWindowEditor::queryClose() +// bool MainWindowEditor::queryClose() //{ // if (!m_repository->modified()) { // return true; // } // int result = KMessageBox::warningYesNoCancel(nullptr, i18nc("@info", // "The currently open course contains unsaved changes. Do you want to save them?")); // switch(result) { // case KMessageBox::Yes: // m_repository->sync(); // return true; // case KMessageBox::No: // return true; // default: // return false; // } //} diff --git a/src/mainwindow_editor.h b/src/mainwindow_editor.h index 51fe36f..4d0656b 100644 --- a/src/mainwindow_editor.h +++ b/src/mainwindow_editor.h @@ -1,63 +1,63 @@ /* * Copyright 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 MAINWINDOW_EDITOR_H #define MAINWINDOW_EDITOR_H -#include #include "core/contributorrepository.h" #include "core/trainingsession.h" +#include class EditorSession; class QQuickWidget; class MainWindowEditor : public QQmlApplicationEngine { Q_OBJECT public: /** * Default Constructor */ MainWindowEditor(ContributorRepository *repository); /** * Default Destructor */ virtual ~MainWindowEditor(); - ContributorRepository * resourceRepository() const; + ContributorRepository *resourceRepository() const; void setupActions(); public Q_SLOTS: void showSettingsDialog(); void save(); void quit(); Q_SIGNALS: - void modeChanged(bool); + void modeChanged(bool); private: ContributorRepository *m_repository; EditorSession *m_editorSession; }; #endif diff --git a/src/models/coursefiltermodel.cpp b/src/models/coursefiltermodel.cpp index d918efa..0d10698 100644 --- a/src/models/coursefiltermodel.cpp +++ b/src/models/coursefiltermodel.cpp @@ -1,96 +1,94 @@ /* * Copyright 2014 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 "coursefiltermodel.h" -#include "models/coursemodel.h" #include "../core/language.h" +#include "artikulate_debug.h" +#include "models/coursemodel.h" #include #include #include -#include "artikulate_debug.h" -CourseFilterModel::CourseFilterModel(QObject* parent) +CourseFilterModel::CourseFilterModel(QObject *parent) : QSortFilterProxyModel(parent) , m_courseModel(nullptr) { - } -CourseModel * CourseFilterModel::courseModel() const +CourseModel *CourseFilterModel::courseModel() const { return m_courseModel; } -Language * CourseFilterModel::language() const +Language *CourseFilterModel::language() const { return m_language; } void CourseFilterModel::setLanguage(Language *language) { if (m_language == language) { return; } m_language = language; emit languageChanged(); invalidateFilter(); emit filteredCountChanged(); } void CourseFilterModel::setCourseModel(CourseModel *courseModel) { if (courseModel == m_courseModel) { return; } m_courseModel = courseModel; setSourceModel(m_courseModel); sort(0); emit courseModelChanged(); emit filteredCountChanged(); } int CourseFilterModel::filteredCount() const { return rowCount(); } bool CourseFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { return QSortFilterProxyModel::lessThan(left, right); } bool CourseFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); if (m_language == nullptr) { return true; - } - else if (sourceModel()->data(index, CourseModel::LanguageRole).value()->id() == m_language->id()) { + } else if (sourceModel()->data(index, CourseModel::LanguageRole).value()->id() == m_language->id()) { return true; } return false; } QVariant CourseFilterModel::course(int row) const { return m_courseModel->data(m_courseModel->index(row, 0), CourseModel::DataRole); } diff --git a/src/models/coursefiltermodel.h b/src/models/coursefiltermodel.h index 5cc41d8..26cd7c4 100644 --- a/src/models/coursefiltermodel.h +++ b/src/models/coursefiltermodel.h @@ -1,58 +1,58 @@ /* * Copyright 2014-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 COURSEFILTERMODEL_H #define COURSEFILTERMODEL_H #include class Course; class CourseModel; class Language; class CourseFilterModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(CourseModel *courseModel READ courseModel WRITE setCourseModel NOTIFY courseModelChanged) Q_PROPERTY(int filteredCount READ filteredCount NOTIFY filteredCountChanged) Q_PROPERTY(Language *language READ language WRITE setLanguage NOTIFY languageChanged) public: explicit CourseFilterModel(QObject *parent = nullptr); - CourseModel * courseModel() const; - void setCourseModel(CourseModel* courseModel); + CourseModel *courseModel() const; + void setCourseModel(CourseModel *courseModel); int filteredCount() const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; void setLanguage(Language *language); - Language * language() const; + Language *language() const; Q_INVOKABLE QVariant course(int row) const; Q_SIGNALS: void courseModelChanged(); void filteredCountChanged(); void languageChanged(); private: - CourseModel *m_courseModel{ nullptr }; - Language *m_language{ nullptr }; + CourseModel *m_courseModel {nullptr}; + Language *m_language {nullptr}; }; #endif diff --git a/src/models/coursemodel.cpp b/src/models/coursemodel.cpp index c90a1ac..bb3572d 100644 --- a/src/models/coursemodel.cpp +++ b/src/models/coursemodel.cpp @@ -1,184 +1,182 @@ /* * Copyright 2013 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 "coursemodel.h" #include "application.h" #include "artikulate_debug.h" +#include "core/icourse.h" #include "core/ilanguage.h" #include "core/iresourcerepository.h" -#include "core/icourse.h" -#include #include +#include CourseModel::CourseModel(QObject *parent) : CourseModel(artikulateApp->resourceRepository(), parent) { } CourseModel::CourseModel(IResourceRepository *repository, QObject *parent) : QAbstractListModel(parent) { setResourceRepository(repository); } -QHash< int, QByteArray > CourseModel::roleNames() const +QHash CourseModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[I18nTitleRole] = "i18nTitle"; roles[DescriptionRole] = "description"; roles[IdRole] = "id"; roles[LanguageRole] = "language"; roles[DataRole] = "dataRole"; return roles; } void CourseModel::setResourceRepository(IResourceRepository *resourceRepository) { for (auto &connection : m_updateConnections) { QObject::disconnect(connection); } m_updateConnections.clear(); if (resourceRepository == nullptr) { qCWarning(ARTIKULATE_CORE()) << "Setting resource repository to nullptr, this shall never happen"; } Q_ASSERT(resourceRepository != nullptr); if (m_resourceRepository == resourceRepository) { qCWarning(ARTIKULATE_CORE()) << "Skipping repository setting, it does not change"; return; } beginResetModel(); if (m_resourceRepository) { disconnect(m_resourceRepository, &IResourceRepository::courseAboutToBeAdded, this, &CourseModel::onCourseAboutToBeAdded); disconnect(m_resourceRepository, &IResourceRepository::courseAdded, this, &CourseModel::onCourseAdded); disconnect(m_resourceRepository, &IResourceRepository::courseAboutToBeRemoved, this, &CourseModel::onCourseAboutToBeRemoved); } m_resourceRepository = resourceRepository; if (m_resourceRepository) { connect(m_resourceRepository, &IResourceRepository::courseAboutToBeAdded, this, &CourseModel::onCourseAboutToBeAdded); connect(m_resourceRepository, &IResourceRepository::courseAdded, this, &CourseModel::onCourseAdded); connect(m_resourceRepository, &IResourceRepository::courseAboutToBeRemoved, this, &CourseModel::onCourseAboutToBeRemoved); } if (m_resourceRepository) { auto courses = m_resourceRepository->courses(); for (int i = 0; i < courses.count(); ++i) { auto course = courses.at(i); // TODO only title changed is connected, change this to a general changed signal - auto connection = connect(course.get(), &ICourse::titleChanged, this, [=](){ + auto connection = connect(course.get(), &ICourse::titleChanged, this, [=]() { const auto row = m_resourceRepository->courses().indexOf(course); emit dataChanged(index(row, 0), index(row, 0)); }); m_updateConnections.insert(i, connection); } } endResetModel(); } -IResourceRepository * CourseModel::resourceRepository() const +IResourceRepository *CourseModel::resourceRepository() const { return m_resourceRepository; } -QVariant CourseModel::data(const QModelIndex& index, int role) const +QVariant CourseModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_resourceRepository) { return QVariant(); } if (index.row() >= rowCount()) { return QVariant(); } auto const course = m_resourceRepository->courses().at(index.row()); - switch(role) - { - case Qt::DisplayRole: - return !course->title().isEmpty()? - QVariant(course->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(course->title()); - case TitleRole: - return course->title(); - case I18nTitleRole: - return course->i18nTitle(); - case DescriptionRole: - return course->description(); - case IdRole: - return course->id(); - case LanguageRole: - return QVariant::fromValue(course->language().get()); - case DataRole: - return QVariant::fromValue(course.get()); - default: - return QVariant(); + switch (role) { + case Qt::DisplayRole: + return !course->title().isEmpty() ? QVariant(course->title()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(course->title()); + case TitleRole: + return course->title(); + case I18nTitleRole: + return course->i18nTitle(); + case DescriptionRole: + return course->description(); + case IdRole: + return course->id(); + case LanguageRole: + return QVariant::fromValue(course->language().get()); + case DataRole: + return QVariant::fromValue(course.get()); + default: + return QVariant(); } } -int CourseModel::rowCount(const QModelIndex&) const +int CourseModel::rowCount(const QModelIndex &) const { if (!m_resourceRepository) { return 0; } return m_resourceRepository->courses().count(); } void CourseModel::onCourseAboutToBeAdded(std::shared_ptr course, int row) { beginInsertRows(QModelIndex(), row, row); - auto connection = connect(course.get(), &ICourse::titleChanged, this, [=](){ + auto connection = connect(course.get(), &ICourse::titleChanged, this, [=]() { const auto row = m_resourceRepository->courses().indexOf(course); emit dataChanged(index(row, 0), index(row, 0)); }); m_updateConnections.insert(row, connection); } void CourseModel::onCourseAdded() { endInsertRows(); } void CourseModel::onCourseAboutToBeRemoved(int row) { beginRemoveRows(QModelIndex(), row, row); QObject::disconnect(m_updateConnections.at(row)); m_updateConnections.removeAt(row); endRemoveRows(); } QVariant CourseModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Course")); } QVariant CourseModel::course(int row) const { return data(index(row, 0), CourseModel::DataRole); } diff --git a/src/models/coursemodel.h b/src/models/coursemodel.h index 82ec289..6bb8ef1 100644 --- a/src/models/coursemodel.h +++ b/src/models/coursemodel.h @@ -1,69 +1,62 @@ /* * 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 . */ #ifndef COURSEMODEL_H #define COURSEMODEL_H #include "artikulatecore_export.h" #include #include class IResourceRepository; class ICourse; class Language; class ARTIKULATECORE_EXPORT CourseModel : public QAbstractListModel { Q_OBJECT public: - enum courseRoles { - TitleRole = Qt::UserRole + 1, - I18nTitleRole, - DescriptionRole, - IdRole, - LanguageRole, - DataRole - }; + enum courseRoles { TitleRole = Qt::UserRole + 1, I18nTitleRole, DescriptionRole, IdRole, LanguageRole, DataRole }; explicit CourseModel(QObject *parent = nullptr); CourseModel(IResourceRepository *repository, QObject *parent = nullptr); ~CourseModel() override = default; - QHash roleNames() const override; - IResourceRepository * resourceRepository() const; + QHash roleNames() const override; + IResourceRepository *resourceRepository() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_INVOKABLE QVariant course(int index) const; protected: void setResourceRepository(IResourceRepository *resourceRepository); private Q_SLOTS: void onCourseAboutToBeAdded(std::shared_ptr course, int index); void onCourseAdded(); void onCourseAboutToBeRemoved(int row); private: - IResourceRepository *m_resourceRepository{ nullptr }; + IResourceRepository *m_resourceRepository {nullptr}; QVector m_updateConnections; }; #endif // COURSEMODEL_H diff --git a/src/models/languagemodel.cpp b/src/models/languagemodel.cpp index 67785d8..343997d 100644 --- a/src/models/languagemodel.cpp +++ b/src/models/languagemodel.cpp @@ -1,81 +1,81 @@ /* * 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 "languagemodel.h" #include "models/languageresourcemodel.h" -#include #include "artikulate_debug.h" #include +#include -LanguageModel::LanguageModel(QObject* parent) +LanguageModel::LanguageModel(QObject *parent) : QSortFilterProxyModel(parent) , m_resourceModel(nullptr) , m_view(NonEmptyGhnsOnlyLanguages) { setDynamicSortFilter(true); } -LanguageResourceModel * LanguageModel::resourceModel() const +LanguageResourceModel *LanguageModel::resourceModel() const { return m_resourceModel; } void LanguageModel::setView(LanguageResourceView view) { // always change view for resource model if (!m_resourceModel) { return; } m_resourceModel->setView(view); // set local view variable if (m_view == view) { return; } m_view = view; emit viewChanged(); } LanguageModel::LanguageResourceView LanguageModel::view() const { return m_view; } void LanguageModel::setResourceModel(LanguageResourceModel *resourceModel) { if (resourceModel != m_resourceModel) { m_resourceModel = resourceModel; m_resourceModel->setView(m_view); setSourceModel(m_resourceModel); sort(0); emit resourceModelChanged(); } } bool LanguageModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { return QSortFilterProxyModel::lessThan(left, right); } QVariant LanguageModel::language(int row) const { return data(index(row, 0), LanguageResourceModel::DataRole); } diff --git a/src/models/languagemodel.h b/src/models/languagemodel.h index 57ed4f9..26b88e7 100644 --- a/src/models/languagemodel.h +++ b/src/models/languagemodel.h @@ -1,61 +1,56 @@ /* * 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 LANGUAGEMODEL_H #define LANGUAGEMODEL_H #include class LanguageResourceModel; class Language; class LanguageModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(LanguageResourceModel *resourceModel READ resourceModel WRITE setResourceModel NOTIFY resourceModelChanged) Q_PROPERTY(LanguageResourceView view READ view WRITE setView NOTIFY viewChanged) public: - enum LanguageResourceView { - NonEmptyContributorOnlyResources, - NonEmptyGhnsOnlyLanguages, - NonEmptyLanguages, - AllLanguages - }; + enum LanguageResourceView { NonEmptyContributorOnlyResources, NonEmptyGhnsOnlyLanguages, NonEmptyLanguages, AllLanguages }; Q_ENUM(LanguageResourceView) explicit LanguageModel(QObject *parent = nullptr); - LanguageResourceModel * resourceModel() const; + LanguageResourceModel *resourceModel() const; void setResourceModel(LanguageResourceModel *resourceModel); bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; void setView(LanguageResourceView view); LanguageResourceView view() const; Q_INVOKABLE QVariant language(int index) const; Q_SIGNALS: void resourceModelChanged(); void viewChanged(); private: LanguageResourceModel *m_resourceModel; LanguageResourceView m_view; }; #endif diff --git a/src/models/languageresourcemodel.cpp b/src/models/languageresourcemodel.cpp index c6bf62a..c275ca7 100644 --- a/src/models/languageresourcemodel.cpp +++ b/src/models/languageresourcemodel.cpp @@ -1,204 +1,202 @@ /* * Copyright 2013 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 "languageresourcemodel.h" #include "application.h" -#include "core/language.h" #include "core/iresourcerepository.h" +#include "core/language.h" +#include "artikulate_debug.h" +#include #include #include -#include -#include "artikulate_debug.h" -LanguageResourceModel::LanguageResourceModel(QObject* parent) +LanguageResourceModel::LanguageResourceModel(QObject *parent) : QAbstractListModel(parent) , m_repository(nullptr) , m_view(LanguageModel::NonEmptyGhnsOnlyLanguages) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitLanguageChanged(int))); setResourceRepository(artikulateApp->resourceRepository()); } -QHash< int, QByteArray > LanguageResourceModel::roleNames() const +QHash LanguageResourceModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[I18nTitleRole] = "i18nTitle"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; roles[CourseNumberRole] = "courseNumberRole"; return roles; } void LanguageResourceModel::setResourceRepository(IResourceRepository *repository) { if (m_repository == repository) { return; } if (m_repository) { m_repository->disconnect(this); } m_repository = repository; updateDisplayedLanguages(); emit resourceRepositoryChanged(); } -IResourceRepository * LanguageResourceModel::resourceRepository() const +IResourceRepository *LanguageResourceModel::resourceRepository() const { return m_repository; } QVariant LanguageResourceModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() >= m_languages.count()) { return QVariant(); } - ILanguage * const language = m_languages.at(index.row()); - switch(role) - { - case Qt::DisplayRole: - return !language->title().isEmpty() ? - QVariant(language->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(language->title()); - case TitleRole: - return language->title(); - case I18nTitleRole: - return language->i18nTitle(); - case IdRole: - return language->id(); - case DataRole: - return QVariant::fromValue(language); - case CourseNumberRole: - return m_languages.count(); - default: - return QVariant(); + ILanguage *const language = m_languages.at(index.row()); + switch (role) { + case Qt::DisplayRole: + return !language->title().isEmpty() ? QVariant(language->title()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(language->title()); + case TitleRole: + return language->title(); + case I18nTitleRole: + return language->i18nTitle(); + case IdRole: + return language->id(); + case DataRole: + return QVariant::fromValue(language); + case CourseNumberRole: + return m_languages.count(); + default: + return QVariant(); } } int LanguageResourceModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_languages.count(); } void LanguageResourceModel::onLanguageAboutToBeAdded(Language *language, int index) { beginInsertRows(QModelIndex(), index, index); m_languages.append(language); connect(language, SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); connect(language, SIGNAL(phonemesChanged()), m_signalMapper, SLOT(map())); connect(language, SIGNAL(phonemeGroupsChanged()), m_signalMapper, SLOT(map())); } void LanguageResourceModel::onLanguageAdded() { updateMappings(); endInsertRows(); } void LanguageResourceModel::onLanguageAboutToBeRemoved(int index) { if (!m_repository) { return; } ILanguage *originalLanguage = m_repository->languages().at(index).get(); int modelIndex = m_languages.indexOf(originalLanguage); if (modelIndex == -1) { qCWarning(ARTIKULATE_LOG()) << "Cannot remove language from model, not registered"; return; } beginRemoveRows(QModelIndex(), modelIndex, modelIndex); originalLanguage->disconnect(m_signalMapper); m_languages.removeAt(modelIndex); } void LanguageResourceModel::onLanguageRemoved() { endRemoveRows(); } void LanguageResourceModel::emitLanguageChanged(int row) { emit languageChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant LanguageResourceModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Language")); } void LanguageResourceModel::setView(LanguageModel::LanguageResourceView view) { if (m_view == view) { return; } m_view = view; updateDisplayedLanguages(); } void LanguageResourceModel::updateDisplayedLanguages() { beginResetModel(); m_languages.clear(); if (m_repository) { m_languages.clear(); - for (auto language: m_repository->languages()) { + for (auto language : m_repository->languages()) { m_languages.append(language.get()); } } updateMappings(); endResetModel(); } LanguageModel::LanguageResourceView LanguageResourceModel::view() const { return m_view; } void LanguageResourceModel::updateMappings() { int languages = m_languages.count(); for (int i = 0; i < languages; i++) { m_signalMapper->setMapping(m_languages.at(i), i); } } diff --git a/src/models/languageresourcemodel.h b/src/models/languageresourcemodel.h index 12035ee..f90aeed 100644 --- a/src/models/languageresourcemodel.h +++ b/src/models/languageresourcemodel.h @@ -1,78 +1,72 @@ /* * 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 LANGUAGERESOURCEMODEL_H #define LANGUAGERESOURCEMODEL_H -#include #include "languagemodel.h" +#include class IResourceRepository; class ILanguage; class QSignalMapper; class LanguageResourceModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(IResourceRepository *repository READ resourceRepository WRITE setResourceRepository NOTIFY resourceRepositoryChanged) public: - enum LanguageRoles { - TitleRole = Qt::UserRole + 1, - I18nTitleRole, - IdRole, - DataRole, - CourseNumberRole - }; + enum LanguageRoles { TitleRole = Qt::UserRole + 1, I18nTitleRole, IdRole, DataRole, CourseNumberRole }; explicit LanguageResourceModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setResourceRepository(IResourceRepository *repository); - IResourceRepository * resourceRepository() const; + IResourceRepository *resourceRepository() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; void setView(LanguageModel::LanguageResourceView view); LanguageModel::LanguageResourceView view() const; Q_SIGNALS: void languageChanged(int index); void resourceRepositoryChanged(); private Q_SLOTS: void onLanguageAboutToBeAdded(Language *resource, int index); void onLanguageAdded(); void onLanguageAboutToBeRemoved(int index); void onLanguageRemoved(); void emitLanguageChanged(int row); void updateDisplayedLanguages(); private: void updateMappings(); IResourceRepository *m_repository; QVector m_languages; LanguageModel::LanguageResourceView m_view; QSignalMapper *m_signalMapper; }; #endif diff --git a/src/models/learningprogressmodel.cpp b/src/models/learningprogressmodel.cpp index c21bad8..f7fa89e 100644 --- a/src/models/learningprogressmodel.cpp +++ b/src/models/learningprogressmodel.cpp @@ -1,167 +1,164 @@ /* * Copyright 2013 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 "learningprogressmodel.h" +#include "artikulate_debug.h" #include "core/trainingsession.h" -#include #include -#include "artikulate_debug.h" +#include LearningProgressModel::LearningProgressModel(QObject *parent) : QAbstractTableModel(parent) , m_session(nullptr) { - } -QHash< int, QByteArray > LearningProgressModel::roleNames() const +QHash LearningProgressModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[DataRole] = "dataRole"; return roles; } -int LearningProgressModel::rowCount(const QModelIndex& parent) const +int LearningProgressModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) if (m_session == 0) { return 0; } // row for every try, plus extra column for 0st and (max + 1)st try return m_session->maximumTries() + 2; } int LearningProgressModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) // we have 4 different word types return 4; } -TrainingSession * LearningProgressModel::session() const +TrainingSession *LearningProgressModel::session() const { return m_session; } void LearningProgressModel::setSession(TrainingSession *session) { if (m_session == session) { return; } beginResetModel(); if (m_session) { m_session->disconnect(this); } m_session = session; connect(session, SIGNAL(finished()), this, SLOT(updateResults())); connect(session, SIGNAL(finished()), this, SIGNAL(maximumTriesChanged())); endResetModel(); emit sessionChanged(); } int LearningProgressModel::maximumTries() const { if (!m_session) { return 0; } return m_session->maximumTries(); } int LearningProgressModel::maximumPhrasesPerTry() const { if (!m_session) { return 0; } return m_session->maximumPhrasesPerTry(); } QVariant LearningProgressModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qCWarning(ARTIKULATE_LOG) << "Invalid index requested"; return QVariant(); } // column tooltip is number of needed tries // first try is 0 if (role == Qt::ToolTipRole) { return QVariant(index.row()); } // otherwise we only support displayrole if (role != Qt::DisplayRole) { return QVariant(); } // handle special rows if (index.row() == 0 || index.row() == m_session->maximumTries() + 1) { return QVariant(0); } // normal tries int tries = index.row(); - switch (index.column()) - { - case Phrase::Word: - return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Word, tries)); - case Phrase::Sentence: - return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Sentence, tries)); - case Phrase::Expression: - return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Expression, tries)); - case Phrase::Paragraph: - return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Paragraph, tries)); - default: - return QVariant(); + switch (index.column()) { + case Phrase::Word: + return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Word, tries)); + case Phrase::Sentence: + return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Sentence, tries)); + case Phrase::Expression: + return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Expression, tries)); + case Phrase::Paragraph: + return QVariant(m_session->numberPhrasesGroupedByTries(TrainingSession::Paragraph, tries)); + default: + return QVariant(); } } QVariant LearningProgressModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QAbstractTableModel::headerData(section, orientation, role); } - switch (section) - { - case Phrase::Word: - return QVariant(i18n("Words")); - case Phrase::Sentence: - return QVariant(i18n("Sentences")); - case Phrase::Expression: - return QVariant(i18n("Expressions")); - case Phrase::Paragraph: - return QVariant(i18n("Paragraphs")); - default: - return QVariant(); + switch (section) { + case Phrase::Word: + return QVariant(i18n("Words")); + case Phrase::Sentence: + return QVariant(i18n("Sentences")); + case Phrase::Expression: + return QVariant(i18n("Expressions")); + case Phrase::Paragraph: + return QVariant(i18n("Paragraphs")); + default: + return QVariant(); } } void LearningProgressModel::updateResults() { beginResetModel(); - //nothing to do + // nothing to do endResetModel(); } diff --git a/src/models/learningprogressmodel.h b/src/models/learningprogressmodel.h index bc7c57c..5fc48ca 100644 --- a/src/models/learningprogressmodel.h +++ b/src/models/learningprogressmodel.h @@ -1,70 +1,65 @@ /* * 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 LEARNINGPROGRESSMODEL_H #define LEARNINGPROGRESSMODEL_H -#include #include +#include class TrainingSession; class LearningProgressModel : public QAbstractTableModel { Q_OBJECT Q_PROPERTY(TrainingSession *session READ session WRITE setSession NOTIFY sessionChanged) Q_PROPERTY(int maximumTries READ maximumTries NOTIFY maximumTriesChanged) Q_PROPERTY(int maximumPhrasesPerTry READ maximumPhrasesPerTry NOTIFY maximumTriesChanged) public: - enum unitRoles { - TitleRole = Qt::UserRole + 1, - NumberPhrasesRole, - IdRole, - DataRole - }; + enum unitRoles { TitleRole = Qt::UserRole + 1, NumberPhrasesRole, IdRole, DataRole }; explicit LearningProgressModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setSession(TrainingSession *session); - TrainingSession * session() const; + TrainingSession *session() const; int maximumTries() const; int maximumPhrasesPerTry() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_SIGNALS: void sessionChanged(); void maximumTriesChanged(); private Q_SLOTS: void updateResults(); private: TrainingSession *m_session; int m_maximumTries; }; #endif // LEARNINGPROGRESSMODEL_H diff --git a/src/models/phonemegroupmodel.cpp b/src/models/phonemegroupmodel.cpp index 752f0e5..82473e0 100644 --- a/src/models/phonemegroupmodel.cpp +++ b/src/models/phonemegroupmodel.cpp @@ -1,177 +1,177 @@ /* * Copyright 2013 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 "phonemegroupmodel.h" #include "core/icourse.h" -#include "core/unit.h" #include "core/phonemegroup.h" +#include "core/unit.h" #include #include -#include #include "artikulate_debug.h" +#include PhonemeGroupModel::PhonemeGroupModel(QObject *parent) : QAbstractListModel(parent) , m_course(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitPhonemeGroupChanged(int))); } -QHash< int, QByteArray > PhonemeGroupModel::roleNames() const +QHash PhonemeGroupModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; return roles; } void PhonemeGroupModel::setCourse(ICourse *course) { if (m_course == course) { return; } beginResetModel(); if (m_course) { m_course->disconnect(this); } m_course = course; - //TODO reintroduce phonems into icourse -// if (m_course) { -// connect(m_course, &ICourse::phonemeGroupAboutToBeAdded, this, &PhonemeGroupModel::onPhonemeGroupAboutToBeAdded); -// connect(m_course, &ICourse::phonemeGroupAdded, this, &PhonemeGroupModel::onPhonemeGroupAdded); -// connect(m_course, &ICourse::phonemeGroupAboutToBeRemoved, this, &PhonemeGroupModel::onPhonemeGroupsAboutToBeRemoved); -// connect(m_course, &ICourse::phonemeGroupRemoved, this, &PhonemeGroupModel::onPhonemeGroupsRemoved); -// } + // TODO reintroduce phonems into icourse + // if (m_course) { + // connect(m_course, &ICourse::phonemeGroupAboutToBeAdded, this, &PhonemeGroupModel::onPhonemeGroupAboutToBeAdded); + // connect(m_course, &ICourse::phonemeGroupAdded, this, &PhonemeGroupModel::onPhonemeGroupAdded); + // connect(m_course, &ICourse::phonemeGroupAboutToBeRemoved, this, &PhonemeGroupModel::onPhonemeGroupsAboutToBeRemoved); + // connect(m_course, &ICourse::phonemeGroupRemoved, this, &PhonemeGroupModel::onPhonemeGroupsRemoved); + // } endResetModel(); emit courseChanged(); } -ICourse * PhonemeGroupModel::course() const +ICourse *PhonemeGroupModel::course() const { return m_course; } -QVariant PhonemeGroupModel::data(const QModelIndex& index, int role) const +QVariant PhonemeGroupModel::data(const QModelIndex &index, int role) const { // TODO: currently not phonems supported in icourse return QVariant(); -// Q_ASSERT(m_course); - -// if (!index.isValid()) { -// return QVariant(); -// } - -// if (index.row() >= m_course->phonemeGroupList().count()) { -// return QVariant(); -// } - -// PhonemeGroup * const phonemeGroup = m_course->phonemeGroupList().at(index.row()); - -// switch(role) -// { -// case Qt::DisplayRole: -// return !phonemeGroup->title().isEmpty()? -// QVariant(phonemeGroup->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); -// case Qt::ToolTipRole: -// return QVariant(phonemeGroup->title()); -// case TitleRole: -// return phonemeGroup->title(); -// case IdRole: -// return phonemeGroup->id(); -// case DataRole: -// return QVariant::fromValue(phonemeGroup); -// default: -// return QVariant(); -// } + // Q_ASSERT(m_course); + + // if (!index.isValid()) { + // return QVariant(); + // } + + // if (index.row() >= m_course->phonemeGroupList().count()) { + // return QVariant(); + // } + + // PhonemeGroup * const phonemeGroup = m_course->phonemeGroupList().at(index.row()); + + // switch(role) + // { + // case Qt::DisplayRole: + // return !phonemeGroup->title().isEmpty()? + // QVariant(phonemeGroup->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); + // case Qt::ToolTipRole: + // return QVariant(phonemeGroup->title()); + // case TitleRole: + // return phonemeGroup->title(); + // case IdRole: + // return phonemeGroup->id(); + // case DataRole: + // return QVariant::fromValue(phonemeGroup); + // default: + // return QVariant(); + // } } -int PhonemeGroupModel::rowCount(const QModelIndex& parent) const +int PhonemeGroupModel::rowCount(const QModelIndex &parent) const { - //TODO currently not phonems supported + // TODO currently not phonems supported return 0; -// if (!m_course) { -// return 0; -// } + // if (!m_course) { + // return 0; + // } -// if (parent.isValid()) { -// return 0; -// } + // if (parent.isValid()) { + // return 0; + // } -// return m_course->phonemeGroupList().count(); + // return m_course->phonemeGroupList().count(); } void PhonemeGroupModel::onPhonemeGroupAboutToBeAdded(PhonemeGroup *phonemeGroup, int index) { connect(phonemeGroup, SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); - //TODO add missing signals + // TODO add missing signals beginInsertRows(QModelIndex(), index, index); } void PhonemeGroupModel::onPhonemeGroupAdded() { updateMappings(); endInsertRows(); } void PhonemeGroupModel::onPhonemeGroupsAboutToBeRemoved(int first, int last) { beginRemoveRows(QModelIndex(), first, last); } void PhonemeGroupModel::onPhonemeGroupsRemoved() { endRemoveRows(); } void PhonemeGroupModel::emitPhonemeGroupChanged(int row) { emit phonemeGroupChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant PhonemeGroupModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Phoneme Group")); } void PhonemeGroupModel::updateMappings() { -// int phonemeGroups = m_course->phonemeGroupList().count(); -// for (int i = 0; i < phonemeGroups; i++) { -// m_signalMapper->setMapping(m_course->phonemeGroupList().at(i), i); -// } + // int phonemeGroups = m_course->phonemeGroupList().count(); + // for (int i = 0; i < phonemeGroups; i++) { + // m_signalMapper->setMapping(m_course->phonemeGroupList().at(i), i); + // } } diff --git a/src/models/phonemegroupmodel.h b/src/models/phonemegroupmodel.h index 4d19579..0350451 100644 --- a/src/models/phonemegroupmodel.h +++ b/src/models/phonemegroupmodel.h @@ -1,70 +1,66 @@ /* * 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 PHONEMEGROUPMODEL_H #define PHONEMEGROUPMODEL_H #include class ICourse; class PhonemeGroup; class QSignalMapper; class PhonemeGroupModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(ICourse *course READ course WRITE setCourse NOTIFY courseChanged) public: - enum unitRoles { - TitleRole = Qt::UserRole + 1, - IdRole, - DataRole - }; + enum unitRoles { TitleRole = Qt::UserRole + 1, IdRole, DataRole }; explicit PhonemeGroupModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setCourse(ICourse *course); - ICourse * course() const; + ICourse *course() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; signals: void phonemeGroupChanged(int index); void courseChanged(); private slots: void onPhonemeGroupAboutToBeAdded(PhonemeGroup *phonemeGroup, int index); void onPhonemeGroupAdded(); void onPhonemeGroupsAboutToBeRemoved(int first, int last); void onPhonemeGroupsRemoved(); void emitPhonemeGroupChanged(int row); private: void updateMappings(); ICourse *m_course; QSignalMapper *m_signalMapper; }; #endif // PHONEMEGROUPMODEL_H diff --git a/src/models/phonememodel.cpp b/src/models/phonememodel.cpp index ba887a6..4121bfe 100644 --- a/src/models/phonememodel.cpp +++ b/src/models/phonememodel.cpp @@ -1,153 +1,151 @@ /* * Copyright 2013 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 "phonememodel.h" #include "core/language.h" #include "core/phoneme.h" #include #include -#include #include "artikulate_debug.h" +#include PhonemeModel::PhonemeModel(QObject *parent) : QAbstractListModel(parent) , m_language(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitPhonemeChanged(int))); } -QHash< int, QByteArray > PhonemeModel::roleNames() const +QHash PhonemeModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; return roles; } -Language * PhonemeModel::language() const +Language *PhonemeModel::language() const { return m_language; } void PhonemeModel::setLanguage(Language *language) { beginResetModel(); m_language = language; emit languageChanged(); endResetModel(); } -QVariant PhonemeModel::data(const QModelIndex& index, int role) const +QVariant PhonemeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() >= m_language->phonemes().count()) { return QVariant(); } auto phoneme = m_language->phonemes().at(index.row()); - switch(role) - { - case Qt::DisplayRole: - return !phoneme->title().isEmpty()? - QVariant(phoneme->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(phoneme->title()); - case TitleRole: - return phoneme->title(); - case IdRole: - return phoneme->id(); - case DataRole: - return QVariant::fromValue(phoneme.get()); - default: - return QVariant(); + switch (role) { + case Qt::DisplayRole: + return !phoneme->title().isEmpty() ? QVariant(phoneme->title()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(phoneme->title()); + case TitleRole: + return phoneme->title(); + case IdRole: + return phoneme->id(); + case DataRole: + return QVariant::fromValue(phoneme.get()); + default: + return QVariant(); } } -int PhonemeModel::rowCount(const QModelIndex& parent) const +int PhonemeModel::rowCount(const QModelIndex &parent) const { if (!m_language) { return 0; } if (parent.isValid()) { return 0; } return m_language->phonemes().count(); } void PhonemeModel::onPhonemeAboutToBeAdded(Phoneme *phoneme, int index) { connect(phoneme, SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); beginInsertRows(QModelIndex(), index, index); } void PhonemeModel::onPhonemeAdded() { updateMappings(); endInsertRows(); } void PhonemeModel::onPhonemesAboutToBeRemoved(int first, int last) { beginRemoveRows(QModelIndex(), first, last); } void PhonemeModel::onPhonemesRemoved() { endRemoveRows(); } void PhonemeModel::emitPhonemeChanged(int row) { emit phonemeChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant PhonemeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Phoneme")); } void PhonemeModel::updateMappings() { if (!m_language) { qCDebug(ARTIKULATE_LOG) << "Aborting to update mappings, language not set."; return; } int phonemes = m_language->phonemes().count(); for (int i = 0; i < phonemes; i++) { m_signalMapper->setMapping(m_language->phonemes().at(i).get(), i); } } diff --git a/src/models/phonememodel.h b/src/models/phonememodel.h index 9df5cd2..608fc6f 100644 --- a/src/models/phonememodel.h +++ b/src/models/phonememodel.h @@ -1,71 +1,66 @@ /* * 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 PHONEMEMODEL_H #define PHONEMEMODEL_H #include class Phoneme; class Language; class QSignalMapper; - class PhonemeModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(Language *language READ language WRITE setLanguage NOTIFY languageChanged) public: - enum courseRoles { - TitleRole = Qt::UserRole + 1, - IdRole, - DataRole - }; + enum courseRoles { TitleRole = Qt::UserRole + 1, IdRole, DataRole }; explicit PhonemeModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setLanguage(Language *language); - Language * language() const; + Language *language() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_SIGNALS: void phonemeChanged(int index); void languageChanged(); private Q_SLOTS: void onPhonemeAboutToBeAdded(Phoneme *phoneme, int index); void onPhonemeAdded(); void onPhonemesAboutToBeRemoved(int first, int last); void onPhonemesRemoved(); void emitPhonemeChanged(int row); private: void updateMappings(); Language *m_language; QSignalMapper *m_signalMapper; }; #endif // PHONEMEMODEL_H diff --git a/src/models/phonemeunitmodel.cpp b/src/models/phonemeunitmodel.cpp index ab62a1d..48dfd87 100644 --- a/src/models/phonemeunitmodel.cpp +++ b/src/models/phonemeunitmodel.cpp @@ -1,216 +1,216 @@ /* * Copyright 2013 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 "phonemeunitmodel.h" #include "core/icourse.h" -#include "core/unit.h" #include "core/phonemegroup.h" +#include "core/unit.h" #include #include -#include #include "artikulate_debug.h" +#include PhonemeUnitModel::PhonemeUnitModel(QObject *parent) : QAbstractListModel(parent) , m_course(nullptr) , m_phonemeGroup(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitUnitChanged(int))); connect(this, &PhonemeUnitModel::phonemeGroupChanged, this, &PhonemeUnitModel::countChanged); connect(this, &PhonemeUnitModel::courseChanged, this, &PhonemeUnitModel::countChanged); } -QHash< int, QByteArray > PhonemeUnitModel::roleNames() const +QHash PhonemeUnitModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[NumberPhrasesRole] = "numberPhrases"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; roles[PhonemeGroupRole] = "phonemeGroupRole"; return roles; } void PhonemeUnitModel::setCourse(ICourse *course) { if (m_course == course) { return; } beginResetModel(); if (m_course) { m_course->disconnect(this); } m_course = course; // TODO currently no phonems supported in icourse -// if (m_course) { -// connect(m_course, &Course::phonemeGroupAboutToBeAdded, this, &PhonemeUnitModel::onUnitAboutToBeAdded); -// connect(m_course, &Course::phonemeGroupAdded, this, &PhonemeUnitModel::onUnitAdded); -// connect(m_course, &Course::phonemeGroupAboutToBeRemoved, this, &PhonemeUnitModel::onUnitsAboutToBeRemoved); -// connect(m_course, &Course::phonemeGroupRemoved, this, &PhonemeUnitModel::onUnitsRemoved); -// } + // if (m_course) { + // connect(m_course, &Course::phonemeGroupAboutToBeAdded, this, &PhonemeUnitModel::onUnitAboutToBeAdded); + // connect(m_course, &Course::phonemeGroupAdded, this, &PhonemeUnitModel::onUnitAdded); + // connect(m_course, &Course::phonemeGroupAboutToBeRemoved, this, &PhonemeUnitModel::onUnitsAboutToBeRemoved); + // connect(m_course, &Course::phonemeGroupRemoved, this, &PhonemeUnitModel::onUnitsRemoved); + // } endResetModel(); emit courseChanged(); } -void PhonemeUnitModel::setPhonemeGroup(PhonemeGroup* phonemeGroup) +void PhonemeUnitModel::setPhonemeGroup(PhonemeGroup *phonemeGroup) { if (m_phonemeGroup == phonemeGroup) { return; } beginResetModel(); m_phonemeGroup = phonemeGroup; endResetModel(); emit phonemeGroupChanged(); } -PhonemeGroup* PhonemeUnitModel::phonemeGroup() const +PhonemeGroup *PhonemeUnitModel::phonemeGroup() const { return m_phonemeGroup; } -ICourse * PhonemeUnitModel::course() const +ICourse *PhonemeUnitModel::course() const { return m_course; } -QVariant PhonemeUnitModel::data(const QModelIndex& index, int role) const +QVariant PhonemeUnitModel::data(const QModelIndex &index, int role) const { - //TODO currently no phonems supported + // TODO currently no phonems supported return QVariant(); -// Q_ASSERT(m_course); -// Q_ASSERT(m_phonemeGroup); - -// if (!index.isValid()) { -// return QVariant(); -// } - -// if (index.row() >= m_course->phonemeUnitList(m_phonemeGroup).count()) { -// return QVariant(); -// } - -// Unit * const unit = m_course->phonemeUnitList(m_phonemeGroup).at(index.row()); - -// switch(role) -// { -// case Qt::DisplayRole: -// return !unit->title().isEmpty()? -// QVariant(unit->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); -// case Qt::ToolTipRole: -// return QVariant(unit->title()); -// case TitleRole: -// return unit->title(); -// case NumberPhrasesRole: -// return unit->phraseList().count(); -// case IdRole: -// return unit->id(); -// case DataRole: -// return QVariant::fromValue(unit); -// case PhonemeGroupRole: -// return QVariant::fromValue(m_course->phonemeGroup(unit)); -// default: -// return QVariant(); -// } -} - -int PhonemeUnitModel::rowCount(const QModelIndex& parent) const + // Q_ASSERT(m_course); + // Q_ASSERT(m_phonemeGroup); + + // if (!index.isValid()) { + // return QVariant(); + // } + + // if (index.row() >= m_course->phonemeUnitList(m_phonemeGroup).count()) { + // return QVariant(); + // } + + // Unit * const unit = m_course->phonemeUnitList(m_phonemeGroup).at(index.row()); + + // switch(role) + // { + // case Qt::DisplayRole: + // return !unit->title().isEmpty()? + // QVariant(unit->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); + // case Qt::ToolTipRole: + // return QVariant(unit->title()); + // case TitleRole: + // return unit->title(); + // case NumberPhrasesRole: + // return unit->phraseList().count(); + // case IdRole: + // return unit->id(); + // case DataRole: + // return QVariant::fromValue(unit); + // case PhonemeGroupRole: + // return QVariant::fromValue(m_course->phonemeGroup(unit)); + // default: + // return QVariant(); + // } +} + +int PhonemeUnitModel::rowCount(const QModelIndex &parent) const { // TODO currently no phonems supported in icourse return 0; -// if (!m_course) { -// return 0; -// } + // if (!m_course) { + // return 0; + // } -// if (parent.isValid()) { -// return 0; -// } + // if (parent.isValid()) { + // return 0; + // } -// return m_course->phonemeUnitList(m_phonemeGroup).count(); + // return m_course->phonemeUnitList(m_phonemeGroup).count(); } void PhonemeUnitModel::onUnitAboutToBeAdded(PhonemeGroup *phonemeGroup, int index) { connect(phonemeGroup, SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); - //TODO add missing signals + // TODO add missing signals beginInsertRows(QModelIndex(), index, index); } void PhonemeUnitModel::onUnitAdded() { updateMappings(); endInsertRows(); emit countChanged(); } void PhonemeUnitModel::onUnitsAboutToBeRemoved(int first, int last) { beginRemoveRows(QModelIndex(), first, last); } void PhonemeUnitModel::onUnitsRemoved() { endRemoveRows(); emit countChanged(); } void PhonemeUnitModel::emitUnitChanged(int row) { emit unitChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant PhonemeUnitModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Phoneme Unit")); } int PhonemeUnitModel::count() const { // TODO currently no phonems supported return 0; -// if (!m_course || !m_phonemeGroup) { -// return 0; -// } -// return m_course->phonemeUnitList(m_phonemeGroup).count(); + // if (!m_course || !m_phonemeGroup) { + // return 0; + // } + // return m_course->phonemeUnitList(m_phonemeGroup).count(); } void PhonemeUnitModel::updateMappings() { -// int units = m_course->phonemeUnitList(m_phonemeGroup).count(); -// for (int i = 0; i < units; i++) { -// m_signalMapper->setMapping(m_course->phonemeUnitList(m_phonemeGroup).at(i), i); -// } + // int units = m_course->phonemeUnitList(m_phonemeGroup).count(); + // for (int i = 0; i < units; i++) { + // m_signalMapper->setMapping(m_course->phonemeUnitList(m_phonemeGroup).at(i), i); + // } } diff --git a/src/models/phonemeunitmodel.h b/src/models/phonemeunitmodel.h index eb9e7ff..c6774ed 100644 --- a/src/models/phonemeunitmodel.h +++ b/src/models/phonemeunitmodel.h @@ -1,82 +1,76 @@ /* * 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 PHONEMEUNITMODEL_H #define PHONEMEUNITMODEL_H #include class PhonemeGroup; class ICourse; class Unit; class PhonemeGroup; class QSignalMapper; class PhonemeUnitModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(ICourse *course READ course WRITE setCourse NOTIFY courseChanged) Q_PROPERTY(PhonemeGroup *phonemeGroup READ phonemeGroup WRITE setPhonemeGroup NOTIFY phonemeGroupChanged) Q_PROPERTY(int count READ count NOTIFY countChanged); public: - enum unitRoles { - TitleRole = Qt::UserRole + 1, - NumberPhrasesRole, - IdRole, - DataRole, - PhonemeGroupRole - }; + enum unitRoles { TitleRole = Qt::UserRole + 1, NumberPhrasesRole, IdRole, DataRole, PhonemeGroupRole }; explicit PhonemeUnitModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setCourse(ICourse *course); - ICourse * course() const; + ICourse *course() const; void setPhonemeGroup(PhonemeGroup *phonemeGroup); - PhonemeGroup * phonemeGroup() const; + PhonemeGroup *phonemeGroup() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int count() const; Q_SIGNALS: void unitChanged(int index); void courseChanged(); void phonemeGroupChanged(); void countChanged(); private Q_SLOTS: void onUnitAboutToBeAdded(PhonemeGroup *phonemeGroup, int index); void onUnitAdded(); void onUnitsAboutToBeRemoved(int first, int last); void onUnitsRemoved(); void emitUnitChanged(int row); private: void updateMappings(); ICourse *m_course; PhonemeGroup *m_phonemeGroup; QSignalMapper *m_signalMapper; }; #endif // PHONEMEUNITMODEL_H diff --git a/src/models/phrasefiltermodel.cpp b/src/models/phrasefiltermodel.cpp index ffb1ae3..829be34 100644 --- a/src/models/phrasefiltermodel.cpp +++ b/src/models/phrasefiltermodel.cpp @@ -1,116 +1,115 @@ /* * Copyright 2013 Andreas Cord-Landwehr * Copyright 2013 Samikshan Bairagya * * 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 "phrasefiltermodel.h" #include "models/phraselistmodel.h" #include -#include #include "artikulate_debug.h" +#include PhraseFilterModel::PhraseFilterModel(QObject *parent) : QSortFilterProxyModel(parent) , m_phraseModel(nullptr) , m_hideExcluded(true) { setHideExcluded(true); } -PhraseListModel * PhraseFilterModel::phraseModel() const +PhraseListModel *PhraseFilterModel::phraseModel() const { return m_phraseModel; } void PhraseFilterModel::setHideExcluded(bool hide) { m_hideExcluded = hide; invalidateFilter(); emit hideExcludedChanged(); } bool PhraseFilterModel::isHideExcluded() const { return m_hideExcluded; } void PhraseFilterModel::setHideNotRecorded(bool hide) { m_hideNotRecorded = hide; invalidateFilter(); emit hideNotRecordedChanged(); } bool PhraseFilterModel::isHideNotRecorded() const { return m_hideNotRecorded; } -void PhraseFilterModel::setPhraseModel(PhraseListModel* phraseModel) +void PhraseFilterModel::setPhraseModel(PhraseListModel *phraseModel) { if (phraseModel == m_phraseModel) { return; } m_phraseModel = phraseModel; setSourceModel(m_phraseModel); sort(0); emit phraseModelChanged(); - } void PhraseFilterModel::setSortOption(PhraseFilterModel::SortOption option) { m_sortOption = option; invalidateFilter(); emit sortOptionChanged(); } PhraseFilterModel::SortOption PhraseFilterModel::sortOption() const { return m_sortOption; } int PhraseFilterModel::filteredCount() const { return rowCount(); } -bool PhraseFilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const +bool PhraseFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { if (m_sortOption == Type) { return sourceModel()->data(left, PhraseListModel::TypeRole).toInt() < sourceModel()->data(right, PhraseListModel::TypeRole).toInt(); } return QSortFilterProxyModel::lessThan(left, right); } bool PhraseFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { int result = true; if (m_hideNotRecorded || m_hideExcluded) { QModelIndex index = sourceModel()->index(source_row, 0, source_parent); bool notRecorded = sourceModel()->data(index, PhraseListModel::SoundFileRole).toUrl().isEmpty(); bool excluded = sourceModel()->data(index, PhraseListModel::ExcludedRole).toBool(); result = !(notRecorded || excluded); } return result; } diff --git a/src/models/phrasefiltermodel.h b/src/models/phrasefiltermodel.h index e1eedca..7b32139 100644 --- a/src/models/phrasefiltermodel.h +++ b/src/models/phrasefiltermodel.h @@ -1,71 +1,68 @@ /* * Copyright 2013-2015 Andreas Cord-Landwehr * Copyright 2013 Samikshan Bairagya * * 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 PHRASEFILTERMODEL_H #define PHRASEFILTERMODEL_H #include class PhraseListModel; class PhraseFilterModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(PhraseListModel *phraseModel READ phraseModel WRITE setPhraseModel NOTIFY phraseModelChanged) Q_PROPERTY(bool hideExcluded READ isHideExcluded WRITE setHideExcluded NOTIFY hideExcludedChanged) Q_PROPERTY(bool hideNotRecorded READ isHideNotRecorded WRITE setHideNotRecorded NOTIFY hideNotRecordedChanged) Q_PROPERTY(SortOption sortOption READ sortOption WRITE setSortOption NOTIFY sortOptionChanged) Q_PROPERTY(int filteredCount READ filteredCount NOTIFY filteredCountChanged) public: Q_ENUMS(SortOption) - enum SortOption { - Id, - Type - }; + enum SortOption { Id, Type }; explicit PhraseFilterModel(QObject *parent = nullptr); - PhraseListModel * phraseModel() const; - void setPhraseModel(PhraseListModel* phraseModel); + PhraseListModel *phraseModel() const; + void setPhraseModel(PhraseListModel *phraseModel); void setSortOption(SortOption option = Id); SortOption sortOption() const; int filteredCount() const; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; - void setHideExcluded(bool hide=true); + void setHideExcluded(bool hide = true); bool isHideExcluded() const; - void setHideNotRecorded(bool hide=true); + void setHideNotRecorded(bool hide = true); bool isHideNotRecorded() const; Q_SIGNALS: void phraseModelChanged(); void hideExcludedChanged(); void hideNotRecordedChanged(); void sortOptionChanged(); void filteredCountChanged(); private: PhraseListModel *m_phraseModel; bool m_hideExcluded; bool m_hideNotRecorded; SortOption m_sortOption; }; #endif diff --git a/src/models/phraselistmodel.cpp b/src/models/phraselistmodel.cpp index e4f148c..c78e833 100644 --- a/src/models/phraselistmodel.cpp +++ b/src/models/phraselistmodel.cpp @@ -1,210 +1,208 @@ /* * Copyright 2013 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 "phraselistmodel.h" -#include "core/unit.h" #include "core/phrase.h" +#include "core/unit.h" +#include #include #include -#include PhraseListModel::PhraseListModel(QObject *parent) : QAbstractListModel(parent) , m_unit(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitPhraseChanged(int))); // connect all phrase number operations to single signal connect(this, &PhraseListModel::typeChanged, this, &PhraseListModel::countChanged); connect(this, &PhraseListModel::unitChanged, this, &PhraseListModel::countChanged); } -QHash< int, QByteArray > PhraseListModel::roleNames() const +QHash PhraseListModel::roleNames() const { QHash roles; roles[TextRole] = "text"; roles[SoundFileRole] = "soundFile"; roles[IdRole] = "id"; roles[TypeRole] = "type"; roles[ExcludedRole] = "excludedRole"; roles[DataRole] = "dataRole"; return roles; } void PhraseListModel::setUnit(Unit *unit) { if (m_unit == unit) { return; } beginResetModel(); if (m_unit) { m_unit->disconnect(this); for (auto &phrase : m_unit->phrases()) { phrase->disconnect(this); } } m_unit = unit; if (m_unit) { // initial setting of signal mappings connect(m_unit, &Unit::phraseAboutToBeAdded, this, &PhraseListModel::onPhraseAboutToBeAdded); connect(m_unit, &Unit::phraseAdded, this, &PhraseListModel::onPhraseAdded); connect(m_unit, &Unit::phraseAboutToBeRemoved, this, &PhraseListModel::onPhrasesAboutToBeRemoved); connect(m_unit, &Unit::phraseRemoved, this, &PhraseListModel::onPhrasesRemoved); // insert and connect all already existing phrases int phrases = m_unit->phrases().count(); for (int i = 0; i < phrases; ++i) { onPhraseAboutToBeAdded(m_unit->phrases().at(i), i); endInsertRows(); emit countChanged(); } updateMappings(); } // emit done endResetModel(); emit unitChanged(); } -Unit * PhraseListModel::unit() const +Unit *PhraseListModel::unit() const { return m_unit; } QVariant PhraseListModel::data(const QModelIndex &index, int role) const { Q_ASSERT(m_unit); if (!index.isValid()) { return QVariant(); } if (index.row() >= m_unit->phrases().count()) { return QVariant(); } std::shared_ptr const phrase = m_unit->phrases().at(index.row()); - switch(role) - { - case Qt::DisplayRole: - return !phrase->text().isEmpty()? - QVariant(phrase->text()): QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(phrase->text()); - case TextRole: - return phrase->text(); - case SoundFileRole: - return phrase->sound(); - case IdRole: - return phrase->id(); - case TypeRole: - return QVariant::fromValue(phrase->type()); -// case ExcludedRole: //FIXME -// return phrase->isExcluded(); - case DataRole: - return QVariant::fromValue(phrase.get()); - default: - return QVariant(); + switch (role) { + case Qt::DisplayRole: + return !phrase->text().isEmpty() ? QVariant(phrase->text()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(phrase->text()); + case TextRole: + return phrase->text(); + case SoundFileRole: + return phrase->sound(); + case IdRole: + return phrase->id(); + case TypeRole: + return QVariant::fromValue(phrase->type()); + // case ExcludedRole: //FIXME + // return phrase->isExcluded(); + case DataRole: + return QVariant::fromValue(phrase.get()); + default: + return QVariant(); } } int PhraseListModel::rowCount(const QModelIndex &parent) const { if (!m_unit) { return 0; } if (parent.isValid()) { return 0; } return m_unit->phrases().count(); } void PhraseListModel::onPhraseAboutToBeAdded(std::shared_ptr phrase, int index) { connect(phrase.get(), SIGNAL(textChanged()), m_signalMapper, SLOT(map())); connect(phrase.get(), SIGNAL(typeChanged()), m_signalMapper, SLOT(map())); connect(phrase.get(), SIGNAL(excludedChanged()), m_signalMapper, SLOT(map())); beginInsertRows(QModelIndex(), index, index); } void PhraseListModel::onPhraseAdded() { updateMappings(); endInsertRows(); emit countChanged(); } void PhraseListModel::onPhrasesAboutToBeRemoved(int first, int last) { beginRemoveRows(QModelIndex(), first, last); } void PhraseListModel::onPhrasesRemoved() { endRemoveRows(); emit countChanged(); } void PhraseListModel::emitPhraseChanged(int row) { beginResetModel(); endResetModel(); - //FIXME very inefficient, but workaround to force new filtering in phrasefiltermodel - // to exclude possible new excluded phrases + // FIXME very inefficient, but workaround to force new filtering in phrasefiltermodel + // to exclude possible new excluded phrases emit phraseChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant PhraseListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Phrase")); } int PhraseListModel::count() const { if (!m_unit) { return 0; } return m_unit->phrases().count(); } void PhraseListModel::updateMappings() { if (!m_unit) { return; } int phrases = m_unit->phrases().count(); for (int i = 0; i < phrases; ++i) { m_signalMapper->setMapping(m_unit->phrases().at(i).get(), i); } } diff --git a/src/models/phraselistmodel.h b/src/models/phraselistmodel.h index 65b302d..49a9713 100644 --- a/src/models/phraselistmodel.h +++ b/src/models/phraselistmodel.h @@ -1,84 +1,77 @@ /* * 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 PHRASELISTMODEL_H #define PHRASELISTMODEL_H -#include #include "core/phrase.h" +#include class Unit; class QSignalMapper; class PhraseListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(Unit *unit READ unit WRITE setUnit NOTIFY unitChanged) Q_PROPERTY(int count READ count NOTIFY countChanged) public: - enum phraseRoles { - TextRole = Qt::UserRole + 1, - IdRole, - TypeRole, - SoundFileRole, - ExcludedRole, - DataRole - }; + enum phraseRoles { TextRole = Qt::UserRole + 1, IdRole, TypeRole, SoundFileRole, ExcludedRole, DataRole }; explicit PhraseListModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setUnit(Unit *unit); - Unit * unit() const; + Unit *unit() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; /** * Count phrases in current model view. If this number is changed, signal * countChanged() is emitted. * * \return number of phrases */ int count() const; Q_SIGNALS: void phraseChanged(int index); void unitChanged(); void typeChanged(); void countChanged(); private Q_SLOTS: void onPhraseAboutToBeAdded(std::shared_ptr unit, int index); void onPhraseAdded(); void onPhrasesAboutToBeRemoved(int first, int last); void onPhrasesRemoved(); void emitPhraseChanged(int row); private: void updateMappings(); Unit *m_unit; QSignalMapper *m_signalMapper; }; #endif diff --git a/src/models/phrasemodel.cpp b/src/models/phrasemodel.cpp index 403930f..496d750 100644 --- a/src/models/phrasemodel.cpp +++ b/src/models/phrasemodel.cpp @@ -1,351 +1,346 @@ /* * 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 "phrasemodel.h" +#include "artikulate_debug.h" #include "core/icourse.h" -#include "core/unit.h" #include "core/phrase.h" +#include "core/unit.h" +#include #include #include -#include -#include "artikulate_debug.h" PhraseModel::PhraseModel(QObject *parent) : QAbstractItemModel(parent) , m_course(nullptr) , m_unitSignalMapper(new QSignalMapper) , m_phraseSignalMapper(new QSignalMapper) { - connect(m_unitSignalMapper, static_cast(&QSignalMapper::mapped), - this, &PhraseModel::onUnitChanged); - connect(m_phraseSignalMapper, static_cast(&QSignalMapper::mapped), - this, &PhraseModel::onPhraseChanged); + connect(m_unitSignalMapper, static_cast(&QSignalMapper::mapped), this, &PhraseModel::onUnitChanged); + connect(m_phraseSignalMapper, static_cast(&QSignalMapper::mapped), this, &PhraseModel::onPhraseChanged); } -QHash< int, QByteArray > PhraseModel::roleNames() const +QHash PhraseModel::roleNames() const { QHash roles; roles[TextRole] = "text"; roles[DataRole] = "dataRole"; return roles; } void PhraseModel::setCourse(ICourse *course) { if (m_course == course) { return; } beginResetModel(); if (m_course) { m_course->disconnect(this); for (auto unit : m_course->units()) { unit->disconnect(this); for (auto &phrase : unit->phrases()) { phrase->disconnect(this); } } } m_course = course; if (m_course) { // connect to unit changes connect(m_course, &ICourse::unitAboutToBeAdded, this, &PhraseModel::onUnitAboutToBeAdded); connect(m_course, &ICourse::unitAdded, this, &PhraseModel::onUnitAdded); connect(m_course, &ICourse::unitsAboutToBeRemoved, this, &PhraseModel::onUnitsAboutToBeRemoved); connect(m_course, &ICourse::unitsRemoved, this, &PhraseModel::onUnitsRemoved); // initial setting of signal mappings for (auto unit : m_course->units()) { // connect to phrase changes connect(unit.get(), &Unit::phraseAboutToBeAdded, this, &PhraseModel::onPhraseAboutToBeAdded); connect(unit.get(), &Unit::phraseAdded, this, &PhraseModel::onPhraseAdded); connect(unit.get(), &Unit::phraseAboutToBeRemoved, this, &PhraseModel::onPhrasesAboutToBeRemoved); connect(unit.get(), &Unit::phraseRemoved, this, &PhraseModel::onPhrasesRemoved); connect(unit.get(), &Unit::titleChanged, m_unitSignalMapper, static_cast(&QSignalMapper::map)); // insert and connect all already existing phrases int phrases = unit->phrases().count(); for (int i = 0; i < phrases; ++i) { onPhraseAboutToBeAdded(unit->phrases().at(i), i); endInsertRows(); } } updateUnitMappings(); updatePhraseMappings(); } // emit done endResetModel(); emit courseChanged(); } -ICourse * PhraseModel::course() const +ICourse *PhraseModel::course() const { return m_course; } QVariant PhraseModel::data(const QModelIndex &index, int role) const { Q_ASSERT(m_course); if (!index.isValid()) { return QVariant(); } if (!index.internalPointer()) { if (!m_course || m_course->units().size() == 0) { return QVariant(); } auto unit = m_course->units().at(index.row()); - switch(role) - { - case TextRole: - return unit->title(); - case DataRole: - return QVariant::fromValue(unit.get()); - default: - return QVariant(); + switch (role) { + case TextRole: + return unit->title(); + case DataRole: + return QVariant::fromValue(unit.get()); + default: + return QVariant(); } - } - else { - Unit *unit = static_cast(index.internalPointer()); - switch(role) - { - case TextRole: - return unit->phrases().at(index.row())->text(); - case DataRole: - return QVariant::fromValue(unit->phrases().at(index.row()).get()); - default: - return QVariant(); + } else { + Unit *unit = static_cast(index.internalPointer()); + switch (role) { + case TextRole: + return unit->phrases().at(index.row())->text(); + case DataRole: + return QVariant::fromValue(unit->phrases().at(index.row()).get()); + default: + return QVariant(); } } } int PhraseModel::rowCount(const QModelIndex &parent) const { if (!m_course) { return 0; } // no valid index -> must be (invisible) root if (!parent.isValid()) { return m_course->units().count(); } // internal pointer -> must be a phrase if (parent.internalPointer()) { return 0; } // else -> must be a unit Unit *unit = m_course->units().at(parent.row()).get(); return unit->phrases().count(); } int PhraseModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; } QModelIndex PhraseModel::parent(const QModelIndex &child) const { if (!child.internalPointer() || !m_course) { return QModelIndex(); } - Unit *parent = static_cast(child.internalPointer()); + Unit *parent = static_cast(child.internalPointer()); for (int i = 0; i < m_course->units().count(); ++i) { if (m_course->units().at(i).get() == parent) { return createIndex(i, 0); } } return QModelIndex(); } QModelIndex PhraseModel::index(int row, int column, const QModelIndex &parent) const { if (!parent.isValid()) { // unit elements return createIndex(row, column); } else { // phrase elements auto unit = m_course->units().at(parent.row()); if (unit) { return createIndex(row, column, unit.get()); } } return QModelIndex(); } QModelIndex PhraseModel::indexPhrase(Phrase *phrase) const { if (!phrase) { return QModelIndex(); } auto unit = phrase->unit(); return createIndex(unit->phrases().indexOf(phrase->self()), 0, unit.get()); } QModelIndex PhraseModel::indexUnit(Unit *unit) const { if (!unit || !m_course) { return QModelIndex(); } - int uIndex{ -1 }; + int uIndex {-1}; for (int i = 0; i < m_course->units().size(); ++i) { if (m_course->units().at(i)->id() == unit->id()) { uIndex = i; break; } } return createIndex(uIndex, 0); } bool PhraseModel::isUnit(const QModelIndex &index) const { return (index.internalPointer() == nullptr); } void PhraseModel::onPhraseAboutToBeAdded(std::shared_ptr phrase, int index) { - int uIndex{ -1 }; + int uIndex {-1}; for (int i = 0; i < m_course->units().size(); ++i) { if (m_course->units().at(i)->id() == phrase->unit()->id()) { uIndex = i; break; } } connect(phrase.get(), &IPhrase::textChanged, m_phraseSignalMapper, static_cast(&QSignalMapper::map)); beginInsertRows(createIndex(uIndex, 0), index, index); } void PhraseModel::onPhraseAdded() { endInsertRows(); updatePhraseMappings(); } void PhraseModel::onPhrasesAboutToBeRemoved(int first, int last) { - //TODO better solution requires access to unit - //TODO remove connections from m_phraseSignalMapper + // TODO better solution requires access to unit + // TODO remove connections from m_phraseSignalMapper beginResetModel(); } void PhraseModel::onPhrasesRemoved() { endResetModel(); } void PhraseModel::onPhraseChanged(QObject *phrase) { - Phrase *changedPhrase = qobject_cast(phrase); + Phrase *changedPhrase = qobject_cast(phrase); Q_ASSERT(changedPhrase); QModelIndex index = indexPhrase(changedPhrase); emit dataChanged(index, index); } void PhraseModel::onUnitAboutToBeAdded(std::shared_ptr unit, int index) { Q_UNUSED(unit) beginInsertRows(QModelIndex(), index, index); connect(unit.get(), &Unit::titleChanged, m_unitSignalMapper, static_cast(&QSignalMapper::map)); } void PhraseModel::onUnitAdded() { endInsertRows(); updateUnitMappings(); } void PhraseModel::onUnitsAboutToBeRemoved(int first, int last) { for (int i = first; i <= last; ++i) { auto unit = m_course->units().at(i); disconnect(unit.get(), &Unit::titleChanged, m_unitSignalMapper, static_cast(&QSignalMapper::map)); } beginRemoveRows(QModelIndex(), first, last); } void PhraseModel::onUnitsRemoved() { endRemoveRows(); } void PhraseModel::onUnitChanged(int index) { emit dataChanged(createIndex(index, 0), createIndex(index, 0)); } QVariant PhraseModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Phrase")); } bool PhraseModel::isPhrase(const QModelIndex &index) const { if (index.internalPointer()) { return true; } return false; } -IPhrase * PhraseModel::phrase(const QModelIndex &index) const +IPhrase *PhraseModel::phrase(const QModelIndex &index) const { if (index.internalPointer()) { Unit *unit = static_cast(index.internalPointer()); return unit->phrases().at(index.row()).get(); } if (!m_course->units().at(index.row())->phrases().isEmpty()) { return m_course->units().at(index.row())->phrases().first().get(); } return nullptr; } -Unit * PhraseModel::unit(const QModelIndex &index) const +Unit *PhraseModel::unit(const QModelIndex &index) const { return m_course->units().at(index.row()).get(); } void PhraseModel::updateUnitMappings() { int units = m_course->units().count(); for (int i = 0; i < units; ++i) { m_unitSignalMapper->setMapping(m_course->units().at(i).get(), i); } } void PhraseModel::updatePhraseMappings() { - //TODO this might be quite costly for long units + // TODO this might be quite costly for long units // better, implement access based on index pairs for (auto unit : m_course->units()) { for (const auto &phrase : unit->phrases()) { m_phraseSignalMapper->setMapping(phrase.get(), phrase.get()); } } } diff --git a/src/models/phrasemodel.h b/src/models/phrasemodel.h index 66538d0..1495059 100644 --- a/src/models/phrasemodel.h +++ b/src/models/phrasemodel.h @@ -1,86 +1,82 @@ /* * 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 PHRASEMODEL_H #define PHRASEMODEL_H -#include -#include #include "core/phrase.h" +#include +#include class ICourse; class QSignalMapper; class PhraseModel : public QAbstractItemModel { Q_OBJECT Q_PROPERTY(ICourse *course READ course WRITE setCourse NOTIFY courseChanged) public: - enum phraseRoles { - TextRole = Qt::UserRole + 1, - IdRole, - DataRole - }; + enum phraseRoles { TextRole = Qt::UserRole + 1, IdRole, DataRole }; explicit PhraseModel(QObject *parent = nullptr); - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setCourse(ICourse *course); - ICourse * course() const; + ICourse *course() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex &child) const override; virtual QModelIndex index(int row, int column, const QModelIndex &parent) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_INVOKABLE bool isPhrase(const QModelIndex &index) const; - Q_INVOKABLE IPhrase * phrase(const QModelIndex &index) const; - Q_INVOKABLE Unit * unit(const QModelIndex &index) const; + Q_INVOKABLE IPhrase *phrase(const QModelIndex &index) const; + Q_INVOKABLE Unit *unit(const QModelIndex &index) const; Q_INVOKABLE QModelIndex indexPhrase(Phrase *phrase) const; Q_INVOKABLE QModelIndex indexUnit(Unit *unit) const; - Q_INVOKABLE bool isUnit(const QModelIndex& index) const; + Q_INVOKABLE bool isUnit(const QModelIndex &index) const; Q_SIGNALS: void phraseChanged(int index); void courseChanged(); void typeChanged(); private Q_SLOTS: void onPhraseAboutToBeAdded(std::shared_ptr phrase, int index); void onPhraseAdded(); void onPhrasesAboutToBeRemoved(int first, int last); void onPhrasesRemoved(); void onPhraseChanged(QObject *phrase); void onUnitAboutToBeAdded(std::shared_ptr unit, int index); void onUnitAdded(); void onUnitsAboutToBeRemoved(int first, int last); void onUnitsRemoved(); void onUnitChanged(int index); private: void updateUnitMappings(); void updatePhraseMappings(); ICourse *m_course; QSignalMapper *m_unitSignalMapper; QSignalMapper *m_phraseSignalMapper; }; #endif diff --git a/src/models/profilemodel.cpp b/src/models/profilemodel.cpp index 1fca67f..34dd841 100644 --- a/src/models/profilemodel.cpp +++ b/src/models/profilemodel.cpp @@ -1,175 +1,173 @@ /* * Copyright 2013 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 "profilemodel.h" -#include "liblearnerprofile/src/profilemanager.h" #include "liblearnerprofile/src/learner.h" +#include "liblearnerprofile/src/profilemanager.h" +#include "artikulate_debug.h" +#include #include #include -#include -#include "artikulate_debug.h" using namespace LearnerProfile; ProfileModel::ProfileModel(QObject *parent) : QAbstractListModel(parent) , m_profileManager(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitProfileChanged(int))); } -QHash< int, QByteArray > ProfileModel::roleNames() const +QHash ProfileModel::roleNames() const { QHash roles; roles[IdRole] = "id"; roles[NameRole] = "name"; roles[DataRole] = "dataRole"; return roles; } void ProfileModel::setProfileManager(ProfileManager *profileManager) { if (m_profileManager == profileManager) { return; } beginResetModel(); if (m_profileManager) { m_profileManager->disconnect(this); foreach (Learner *learner, m_profileManager->profiles()) { learner->disconnect(this); } } m_profileManager = profileManager; if (m_profileManager) { // initial setting of signal mappings connect(m_profileManager, &ProfileManager::profileAdded, this, &ProfileModel::onProfileAdded); connect(m_profileManager, &ProfileManager::profileAboutToBeRemoved, this, &ProfileModel::onProfileAboutToBeRemoved); // insert and connect all already existing profiles int profiles = m_profileManager->profiles().count(); for (int i = 0; i < profiles; ++i) { onProfileAdded(m_profileManager->profiles().at(i), i); } updateMappings(); } endResetModel(); } -ProfileManager * ProfileModel::profileManager() const +ProfileManager *ProfileModel::profileManager() const { return m_profileManager; } QVariant ProfileModel::data(const QModelIndex &index, int role) const { Q_ASSERT(m_profileManager); if (!index.isValid()) { return QVariant(); } if (index.row() >= m_profileManager->profiles().count()) { return QVariant(); } - Learner * const learner = m_profileManager->profiles().at(index.row()); - - switch(role) - { - case Qt::DisplayRole: - return !learner->name().isEmpty()? - QVariant(learner->name()): QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(learner->name()); - case IdRole: - return learner->identifier(); - case NameRole: - return learner->name(); - case DataRole: - return QVariant::fromValue(learner); - default: - return QVariant(); + Learner *const learner = m_profileManager->profiles().at(index.row()); + + switch (role) { + case Qt::DisplayRole: + return !learner->name().isEmpty() ? QVariant(learner->name()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(learner->name()); + case IdRole: + return learner->identifier(); + case NameRole: + return learner->name(); + case DataRole: + return QVariant::fromValue(learner); + default: + return QVariant(); } } int ProfileModel::rowCount(const QModelIndex &parent) const { if (!m_profileManager) { return 0; } if (parent.isValid()) { return 0; } return m_profileManager->profiles().count(); } void ProfileModel::onProfileAdded(Learner *learner, int index) { connect(learner, SIGNAL(nameChanged()), m_signalMapper, SLOT(map())); connect(learner, SIGNAL(identifierChanged()), m_signalMapper, SLOT(map())); beginInsertRows(QModelIndex(), index, index); updateMappings(); endInsertRows(); } void ProfileModel::onProfileAboutToBeRemoved(int index) { beginRemoveRows(QModelIndex(), index, index); endRemoveRows(); } void ProfileModel::emitProfileChanged(int row) { beginResetModel(); endResetModel(); - //FIXME very inefficient, but workaround to force new filtering in phrasefiltermodel - // to exclude possible new excluded phrases + // FIXME very inefficient, but workaround to force new filtering in phrasefiltermodel + // to exclude possible new excluded phrases emit profileChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant ProfileModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Profile")); } void ProfileModel::updateMappings() { if (!m_profileManager) { return; } int profiles = m_profileManager->profiles().count(); for (int i = 0; i < profiles; ++i) { m_signalMapper->setMapping(m_profileManager->profiles().at(i), i); } } diff --git a/src/models/profilemodel.h b/src/models/profilemodel.h index 1464c3c..0ec64a5 100644 --- a/src/models/profilemodel.h +++ b/src/models/profilemodel.h @@ -1,70 +1,67 @@ /* * 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 PROFILEMODEL_H #define PROFILEMODEL_H #include -namespace LearnerProfile { - class Learner; - class ProfileManager; +namespace LearnerProfile +{ +class Learner; +class ProfileManager; } class QSignalMapper; class ProfileModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(LearnerProfile::ProfileManager *profileManager READ profileManager WRITE setProfileManager) public: - enum profileRoles { - NameRole = Qt::UserRole + 1, - IdRole, - DataRole - }; + enum profileRoles { NameRole = Qt::UserRole + 1, IdRole, DataRole }; explicit ProfileModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setProfileManager(LearnerProfile::ProfileManager *profileManager); - LearnerProfile::ProfileManager * profileManager() const; + LearnerProfile::ProfileManager *profileManager() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_SIGNALS: void profileChanged(int index); private Q_SLOTS: void onProfileAdded(LearnerProfile::Learner *learner, int index); void onProfileAboutToBeRemoved(int index); void emitProfileChanged(int row); private: void updateMappings(); LearnerProfile::ProfileManager *m_profileManager; QSignalMapper *m_signalMapper; }; #endif // PROFILEMODEL_H diff --git a/src/models/skeletonmodel.cpp b/src/models/skeletonmodel.cpp index 77f03fb..3a3b4d7 100644 --- a/src/models/skeletonmodel.cpp +++ b/src/models/skeletonmodel.cpp @@ -1,186 +1,177 @@ /* * Copyright 2013 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 "skeletonmodel.h" #include "application.h" #include "core/contributorrepository.h" #include "core/icourse.h" #include "core/resources/skeletonresource.h" #include "artikulate_debug.h" #include #include #include SkeletonModel::SkeletonModel(QObject *parent) : SkeletonModel(artikulateApp->editableRepository(), parent) { } SkeletonModel::SkeletonModel(IEditableRepository *repository, QObject *parent) : QAbstractListModel(parent) { setResourceRepository(repository); } QHash SkeletonModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[DescriptionRole] = "description"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; return roles; } void SkeletonModel::setResourceRepository(IEditableRepository *repository) { if (m_repository == repository) { return; } beginResetModel(); if (m_repository) { - disconnect(m_repository, &IEditableRepository::skeletonAboutToBeAdded, this, - &SkeletonModel::onSkeletonAboutToBeAdded); - disconnect(m_repository, &IEditableRepository::skeletonAdded, this, - &SkeletonModel::onSkeletonAdded); - disconnect(m_repository, &IEditableRepository::skeletonAboutToBeRemoved, this, - &SkeletonModel::onSkeletonAboutToBeRemoved); - disconnect(m_repository, &IEditableRepository::skeletonRemoved, this, - &SkeletonModel::onSkeletonRemoved); + disconnect(m_repository, &IEditableRepository::skeletonAboutToBeAdded, this, &SkeletonModel::onSkeletonAboutToBeAdded); + disconnect(m_repository, &IEditableRepository::skeletonAdded, this, &SkeletonModel::onSkeletonAdded); + disconnect(m_repository, &IEditableRepository::skeletonAboutToBeRemoved, this, &SkeletonModel::onSkeletonAboutToBeRemoved); + disconnect(m_repository, &IEditableRepository::skeletonRemoved, this, &SkeletonModel::onSkeletonRemoved); } m_repository = repository; if (m_repository) { - connect(m_repository, &IEditableRepository::skeletonAboutToBeAdded, this, - &SkeletonModel::onSkeletonAboutToBeAdded); - connect(m_repository, &IEditableRepository::skeletonAdded, this, - &SkeletonModel::onSkeletonAdded); - connect(m_repository, &IEditableRepository::skeletonAboutToBeRemoved, this, - &SkeletonModel::onSkeletonAboutToBeRemoved); - connect(m_repository, &IEditableRepository::skeletonRemoved, this, - &SkeletonModel::onSkeletonRemoved); + connect(m_repository, &IEditableRepository::skeletonAboutToBeAdded, this, &SkeletonModel::onSkeletonAboutToBeAdded); + connect(m_repository, &IEditableRepository::skeletonAdded, this, &SkeletonModel::onSkeletonAdded); + connect(m_repository, &IEditableRepository::skeletonAboutToBeRemoved, this, &SkeletonModel::onSkeletonAboutToBeRemoved); + connect(m_repository, &IEditableRepository::skeletonRemoved, this, &SkeletonModel::onSkeletonRemoved); } if (m_repository) { auto skeletons = m_repository->skeletons(); for (int i = 0; i < skeletons.count(); ++i) { auto skeleton = skeletons.at(i); // TODO only title changed is connected, change this to a general changed signal - auto connection = connect(skeleton.get(), &IEditableCourse::titleChanged, this, [=](){ + auto connection = connect(skeleton.get(), &IEditableCourse::titleChanged, this, [=]() { const auto row = m_repository->skeletons().indexOf(skeleton); emit dataChanged(index(row, 0), index(row, 0)); }); m_updateConnections.insert(i, connection); } } endResetModel(); } -IEditableRepository * SkeletonModel::resourceRepository() const +IEditableRepository *SkeletonModel::resourceRepository() const { return m_repository; } QVariant SkeletonModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || m_repository == nullptr) { return QVariant(); } if (index.row() >= rowCount()) { return QVariant(); } auto skeleton = m_repository->skeletons().at(index.row()); switch (role) { - case Qt::DisplayRole: - return !skeleton->title().isEmpty() ? QVariant(skeleton->title()) - : QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(skeleton->title()); - case TitleRole: - return skeleton->title(); - case DescriptionRole: - return skeleton->description(); - case IdRole: - return skeleton->id(); - case DataRole: - return QVariant::fromValue(skeleton.get()); - default: - return QVariant(); + case Qt::DisplayRole: + return !skeleton->title().isEmpty() ? QVariant(skeleton->title()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(skeleton->title()); + case TitleRole: + return skeleton->title(); + case DescriptionRole: + return skeleton->description(); + case IdRole: + return skeleton->id(); + case DataRole: + return QVariant::fromValue(skeleton.get()); + default: + return QVariant(); } } int SkeletonModel::rowCount(const QModelIndex &) const { if (m_repository == nullptr) { return 0; } return m_repository->skeletons().count(); } void SkeletonModel::onSkeletonAboutToBeAdded(std::shared_ptr skeleton, int row) { beginInsertRows(QModelIndex(), row, row); - auto connection = connect(skeleton.get(), &IEditableCourse::titleChanged, this, [=](){ + auto connection = connect(skeleton.get(), &IEditableCourse::titleChanged, this, [=]() { const auto row = m_repository->courses().indexOf(skeleton); emit dataChanged(index(row, 0), index(row, 0)); }); m_updateConnections.insert(row, connection); } void SkeletonModel::onSkeletonAdded() { endInsertRows(); } void SkeletonModel::onSkeletonAboutToBeRemoved(int row) { beginRemoveRows(QModelIndex(), row, row); QObject::disconnect(m_updateConnections.at(row)); m_updateConnections.removeAt(row); } void SkeletonModel::onSkeletonRemoved() { endRemoveRows(); } QVariant SkeletonModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Skeleton")); } QVariant SkeletonModel::skeleton(int row) const { return data(index(row, 0), SkeletonModel::DataRole); } diff --git a/src/models/skeletonmodel.h b/src/models/skeletonmodel.h index 2440964..f423b5f 100644 --- a/src/models/skeletonmodel.h +++ b/src/models/skeletonmodel.h @@ -1,68 +1,63 @@ /* * 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 . */ #ifndef SKELETONMODEL_H #define SKELETONMODEL_H #include "artikulatecore_export.h" #include #include class IEditableRepository; class IEditableCourse; class ICourse; class ARTIKULATECORE_EXPORT SkeletonModel : public QAbstractListModel { Q_OBJECT public: - enum skeletonRoles { - TitleRole = Qt::UserRole + 1, - DescriptionRole, - IdRole, - DataRole - }; + enum skeletonRoles { TitleRole = Qt::UserRole + 1, DescriptionRole, IdRole, DataRole }; explicit SkeletonModel(QObject *parent = nullptr); SkeletonModel(IEditableRepository *repository, QObject *parent = nullptr); ~SkeletonModel() override = default; - QHash roleNames() const override; - IEditableRepository * resourceRepository() const; + QHash roleNames() const override; + IEditableRepository *resourceRepository() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_INVOKABLE QVariant skeleton(int index) const; protected: void setResourceRepository(IEditableRepository *resourceRepository); private Q_SLOTS: void onSkeletonAboutToBeAdded(std::shared_ptr skeleton, int index); void onSkeletonAdded(); void onSkeletonAboutToBeRemoved(int row); void onSkeletonRemoved(); private: - IEditableRepository *m_repository{ nullptr }; + IEditableRepository *m_repository {nullptr}; QVector m_updateConnections; }; #endif // SKELETONMODEL_H diff --git a/src/models/unitfiltermodel.cpp b/src/models/unitfiltermodel.cpp index 5ce7dcb..500680e 100644 --- a/src/models/unitfiltermodel.cpp +++ b/src/models/unitfiltermodel.cpp @@ -1,67 +1,66 @@ /* * Copyright 2014 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 "unitfiltermodel.h" #include "models/unitmodel.h" #include -#include #include "artikulate_debug.h" +#include -UnitFilterModel::UnitFilterModel(QObject* parent) +UnitFilterModel::UnitFilterModel(QObject *parent) : QSortFilterProxyModel(parent) , m_unitModel(nullptr) { - } -UnitModel * UnitFilterModel::unitModel() const +UnitModel *UnitFilterModel::unitModel() const { return m_unitModel; } -void UnitFilterModel::setUnitModel(UnitModel* unitModel) +void UnitFilterModel::setUnitModel(UnitModel *unitModel) { if (unitModel == m_unitModel) { return; } m_unitModel = unitModel; setSourceModel(m_unitModel); sort(0); emit unitModelChanged(); } int UnitFilterModel::filteredCount() const { return rowCount(); } bool UnitFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { return QSortFilterProxyModel::lessThan(left, right); } bool UnitFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); return sourceModel()->data(index, UnitModel::ContainsTrainingData).toBool(); } diff --git a/src/models/unitfiltermodel.h b/src/models/unitfiltermodel.h index 7142640..69cece3 100644 --- a/src/models/unitfiltermodel.h +++ b/src/models/unitfiltermodel.h @@ -1,52 +1,52 @@ /* * Copyright 2014-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 UNITFILTERMODEL_H #define UNITFILTERMODEL_H #include class UnitModel; class UnitFilterModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(UnitModel *unitModel READ unitModel WRITE setUnitModel NOTIFY unitModelChanged) Q_PROPERTY(int filteredCount READ filteredCount NOTIFY filteredCountChanged) public: explicit UnitFilterModel(QObject *parent = nullptr); - UnitModel * unitModel() const; - void setUnitModel(UnitModel* unitModel); + UnitModel *unitModel() const; + void setUnitModel(UnitModel *unitModel); int filteredCount() const; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; Q_SIGNALS: void unitModelChanged(); void viewChanged(); void sortOptionChanged(); void filteredCountChanged(); private: UnitModel *m_unitModel; }; #endif diff --git a/src/models/unitmodel.cpp b/src/models/unitmodel.cpp index a2bccd8..d6c8c89 100644 --- a/src/models/unitmodel.cpp +++ b/src/models/unitmodel.cpp @@ -1,181 +1,179 @@ /* * Copyright 2013-2014 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 "unitmodel.h" #include "core/icourse.h" -#include "core/unit.h" -#include "core/phrase.h" #include "core/language.h" +#include "core/phrase.h" +#include "core/unit.h" #include #include -#include #include "artikulate_debug.h" +#include UnitModel::UnitModel(QObject *parent) : QAbstractListModel(parent) , m_course(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitUnitChanged(int))); } -QHash< int, QByteArray > UnitModel::roleNames() const +QHash UnitModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[ContainsTrainingData] = "containsTrainingData"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; return roles; } void UnitModel::setCourse(ICourse *course) { if (m_course == course) { return; } beginResetModel(); if (m_course) { m_course->disconnect(this); } m_course = course; if (m_course) { connect(m_course, &ICourse::unitAboutToBeAdded, this, &UnitModel::onUnitAboutToBeAdded); connect(m_course, &ICourse::unitAdded, this, &UnitModel::onUnitAdded); connect(m_course, &ICourse::unitsAboutToBeRemoved, this, &UnitModel::onUnitsAboutToBeRemoved); connect(m_course, &ICourse::unitsRemoved, this, &UnitModel::onUnitsRemoved); } endResetModel(); emit courseChanged(); } -ICourse * UnitModel::course() const +ICourse *UnitModel::course() const { return m_course; } -QVariant UnitModel::data(const QModelIndex& index, int role) const +QVariant UnitModel::data(const QModelIndex &index, int role) const { Q_ASSERT(m_course); if (!index.isValid()) { return QVariant(); } if (index.row() >= m_course->units().count()) { return QVariant(); } auto unit = m_course->units().at(index.row()); - switch(role) - { - case Qt::DisplayRole: - return !unit->title().isEmpty()? - QVariant(unit->title()): QVariant(i18nc("@item:inlistbox:", "unknown")); - case Qt::ToolTipRole: - return QVariant(unit->title()); - case TitleRole: - return unit->title(); - case ContainsTrainingData: - for (const auto &phrase : unit->phrases()) { -// if (phrase->editState() == Phrase::Completed) { //TODO introduce editablephrase -// return true; -// } - } - return false; - case IdRole: - return unit->id(); - case DataRole: - return QVariant::fromValue(unit.get()); - default: - return QVariant(); + switch (role) { + case Qt::DisplayRole: + return !unit->title().isEmpty() ? QVariant(unit->title()) : QVariant(i18nc("@item:inlistbox:", "unknown")); + case Qt::ToolTipRole: + return QVariant(unit->title()); + case TitleRole: + return unit->title(); + case ContainsTrainingData: + for (const auto &phrase : unit->phrases()) { + // if (phrase->editState() == Phrase::Completed) { //TODO introduce editablephrase + // return true; + // } + } + return false; + case IdRole: + return unit->id(); + case DataRole: + return QVariant::fromValue(unit.get()); + default: + return QVariant(); } } -int UnitModel::rowCount(const QModelIndex& parent) const +int UnitModel::rowCount(const QModelIndex &parent) const { if (!m_course) { return 0; } if (parent.isValid()) { return 0; } return m_course->units().count(); } void UnitModel::onUnitAboutToBeAdded(std::shared_ptr unit, int index) { connect(unit.get(), SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); - //TODO add missing signals + // TODO add missing signals beginInsertRows(QModelIndex(), index, index); } void UnitModel::onUnitAdded() { updateMappings(); endInsertRows(); } void UnitModel::onUnitsAboutToBeRemoved(int first, int last) { beginRemoveRows(QModelIndex(), first, last); } void UnitModel::onUnitsRemoved() { endRemoveRows(); } void UnitModel::emitUnitChanged(int row) { emit unitChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } QVariant UnitModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(section + 1); } return QVariant(i18nc("@title:column", "Unit")); } void UnitModel::updateMappings() { int units = m_course->units().count(); for (int i = 0; i < units; i++) { m_signalMapper->setMapping(m_course->units().at(i).get(), i); } } diff --git a/src/models/unitmodel.h b/src/models/unitmodel.h index bea9911..a13ac54 100644 --- a/src/models/unitmodel.h +++ b/src/models/unitmodel.h @@ -1,72 +1,72 @@ /* * 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 UNITMODEL_H #define UNITMODEL_H -#include #include +#include class ICourse; class Unit; class QSignalMapper; class UnitModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(ICourse *course READ course WRITE setCourse NOTIFY courseChanged) public: enum unitRoles { - TitleRole = Qt::UserRole + 1, //!< title of unit - IdRole, //!< unique identifier of unit - ContainsTrainingData, //!< boolean value indicating whether unit has phrase with native recordings - DataRole //!< access to Unit object + TitleRole = Qt::UserRole + 1, //!< title of unit + IdRole, //!< unique identifier of unit + ContainsTrainingData, //!< boolean value indicating whether unit has phrase with native recordings + DataRole //!< access to Unit object }; explicit UnitModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ - virtual QHash roleNames() const override; + virtual QHash roleNames() const override; void setCourse(ICourse *course); - ICourse * course() const; + ICourse *course() const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Q_SIGNALS: void unitChanged(int index); void courseChanged(); private Q_SLOTS: void onUnitAboutToBeAdded(std::shared_ptr unit, int index); void onUnitAdded(); void onUnitsAboutToBeRemoved(int first, int last); void onUnitsRemoved(); void emitUnitChanged(int row); private: void updateMappings(); ICourse *m_course; QSignalMapper *m_signalMapper; }; #endif // UNITMODEL_H diff --git a/src/qmlcontrols/iconitem.cpp b/src/qmlcontrols/iconitem.cpp index 739db1e..af02a7c 100644 --- a/src/qmlcontrols/iconitem.cpp +++ b/src/qmlcontrols/iconitem.cpp @@ -1,168 +1,167 @@ /* * Copyright 2011 Marco Martin * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "iconitem.h" -#include -#include -#include #include "imagetexturescache.h" #include "managedtexturenode.h" +#include +#include +#include Q_GLOBAL_STATIC(ImageTexturesCache, s_iconImageCache) IconItem::IconItem(QQuickItem *parent) - : QQuickItem(parent), - m_smooth(false), - m_state(DefaultState), - m_changed(false) + : QQuickItem(parent) + , m_smooth(false) + , m_state(DefaultState) + , m_changed(false) { setFlag(ItemHasContents, true); } - IconItem::~IconItem() { } void IconItem::setIcon(const QVariant &icon) { - if(icon.canConvert()) { + if (icon.canConvert()) { m_icon = icon.value(); - } else if(icon.canConvert()) { + } else if (icon.canConvert()) { m_icon = QIcon::fromTheme(icon.toString()); } else { m_icon = QIcon(); } m_changed = true; update(); } QIcon IconItem::icon() const { return m_icon; } IconItem::State IconItem::state() const { return m_state; } void IconItem::setState(IconItem::State state) { if (m_state == state) { return; } m_state = state; m_changed = true; emit stateChanged(state); update(); } bool IconItem::enabled() const { return (m_state == DefaultState); } void IconItem::setEnabled(bool enabled) { if (enabled) { setState(DefaultState); } else { setState(DisabledState); } } int IconItem::implicitWidth() const { return 32; } int IconItem::implicitHeight() const { return 32; } void IconItem::setSmooth(const bool smooth) { if (smooth == m_smooth) { return; } m_smooth = smooth; m_changed = true; update(); } bool IconItem::smooth() const { return m_smooth; } -QSGNode* IconItem::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/) +QSGNode *IconItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData * /*data*/) { if (m_icon.isNull()) { delete node; return nullptr; } if (m_changed || node == nullptr) { m_changed = false; - ManagedTextureNode* mNode = dynamic_cast(node); - if(!mNode) { + ManagedTextureNode *mNode = dynamic_cast(node); + if (!mNode) { delete node; mNode = new ManagedTextureNode; } QIcon::Mode mode; - switch(m_state) { + switch (m_state) { case DefaultState: mode = QIcon::Normal; break; case ActiveState: mode = QIcon::Active; break; case DisabledState: mode = QIcon::Disabled; break; } QImage img; const QSize size(static_cast(width()), static_cast(height())); if (!size.isEmpty()) { img = m_icon.pixmap(size, mode, QIcon::On).toImage(); } mNode->setTexture(s_iconImageCache->loadTexture(window(), img)); - mNode->setRect(QRect(QPoint(0,0), size)); + mNode->setRect(QRect(QPoint(0, 0), size)); node = mNode; } return node; } void IconItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (newGeometry.size() != oldGeometry.size()) { m_changed = true; update(); } QQuickItem::geometryChanged(newGeometry, oldGeometry); } diff --git a/src/qmlcontrols/iconitem.h b/src/qmlcontrols/iconitem.h index 87ae139..0ea00a3 100644 --- a/src/qmlcontrols/iconitem.h +++ b/src/qmlcontrols/iconitem.h @@ -1,82 +1,81 @@ /*************************************************************************** * Copyright 2011 Marco Martin * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #ifndef ICONITEM_H #define ICONITEM_H #include #include #include #include "artikulatecore_export.h" class ARTIKULATECORE_EXPORT IconItem : public QQuickItem { Q_OBJECT Q_PROPERTY(QVariant icon READ icon WRITE setIcon) Q_PROPERTY(bool smooth READ smooth WRITE setSmooth) Q_PROPERTY(int implicitWidth READ implicitWidth CONSTANT) Q_PROPERTY(int implicitHeight READ implicitHeight CONSTANT) Q_PROPERTY(State state READ state WRITE setState NOTIFY stateChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY stateChanged) Q_ENUMS(State) public: - enum State { - DefaultState, ///The default state. - ActiveState, ///Icon is active. - DisabledState ///Icon is disabled. + DefaultState, /// The default state. + ActiveState, /// Icon is active. + DisabledState /// Icon is disabled. }; explicit IconItem(QQuickItem *parent = nullptr); ~IconItem(); void setIcon(const QVariant &icon); QIcon icon() const; IconItem::State state() const; void setState(State state); int implicitWidth() const; int implicitHeight() const; void setSmooth(const bool smooth); bool smooth() const; void setEnabled(bool enabled = true); bool enabled() const; - QSGNode* updatePaintNode(QSGNode* node, UpdatePaintNodeData* data) override; + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override; Q_SIGNALS: void stateChanged(State state); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; private: QIcon m_icon; bool m_smooth; State m_state; bool m_changed; }; #endif diff --git a/src/qmlcontrols/imagetexturescache.cpp b/src/qmlcontrols/imagetexturescache.cpp index 2bb1c0a..1b687f3 100644 --- a/src/qmlcontrols/imagetexturescache.cpp +++ b/src/qmlcontrols/imagetexturescache.cpp @@ -1,70 +1,69 @@ /* * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "imagetexturescache.h" -#include #include +#include -typedef QHash > > TexturesCache; +typedef QHash>> TexturesCache; -struct ImageTexturesCachePrivate -{ +struct ImageTexturesCachePrivate { TexturesCache cache; }; ImageTexturesCache::ImageTexturesCache() : d(new ImageTexturesCachePrivate) { } ImageTexturesCache::~ImageTexturesCache() { } QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options) { qint64 id = image.cacheKey(); QSharedPointer texture = d->cache.value(id).value(window).toStrongRef(); if (!texture) { - auto cleanAndDelete = [this, window, id](QSGTexture* texture) { - QHash >& textures = (d->cache)[id]; + auto cleanAndDelete = [this, window, id](QSGTexture *texture) { + QHash> &textures = (d->cache)[id]; textures.remove(window); if (textures.isEmpty()) d->cache.remove(id); delete texture; }; texture = QSharedPointer(window->createTextureFromImage(image, options), cleanAndDelete); (d->cache)[id][window] = texture.toWeakRef(); } - //if we have a cache in an atlas but our request cannot use an atlassed texture - //create a new texture and use that - //don't use removedFromAtlas() as that requires keeping a reference to the non atlased version + // if we have a cache in an atlas but our request cannot use an atlassed texture + // create a new texture and use that + // don't use removedFromAtlas() as that requires keeping a reference to the non atlased version if (!(options & QQuickWindow::TextureCanUseAtlas) && texture->isAtlasTexture()) { texture = QSharedPointer(window->createTextureFromImage(image, options)); } return texture; } QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image) { return loadTexture(window, image, nullptr); } diff --git a/src/qmlcontrols/imagetexturescache.h b/src/qmlcontrols/imagetexturescache.h index 6d7b4ab..c2b72ee 100644 --- a/src/qmlcontrols/imagetexturescache.h +++ b/src/qmlcontrols/imagetexturescache.h @@ -1,61 +1,60 @@ /* * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef IMAGETEXTURESCACHE_H #define IMAGETEXTURESCACHE_H -#include #include +#include class QImage; class QSGTexture; struct ImageTexturesCachePrivate; /** * @short Helps to manage textures by creating images and reference counts them. * * Use this class as a factory for textures, when creating them from a QImage * instance. * Keeps track of all the created textures in a map between the QImage::cacheKey() and * the cached texture until it gets de-referenced. * * @see ManagedTextureNode */ class ImageTexturesCache { public: ImageTexturesCache(); ~ImageTexturesCache(); /** * @returns the texture for a given @p window and @p image. * * If an @p image id is the same as one already provided before, we won't create * a new texture and return a shared pointer to the existing texture. */ QSharedPointer loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options); QSharedPointer loadTexture(QQuickWindow *window, const QImage &image); - private: QScopedPointer d; }; #endif // IMAGETEXTURESCACHE_H diff --git a/src/qmlcontrols/managedtexturenode.cpp b/src/qmlcontrols/managedtexturenode.cpp index 408621e..39baac9 100644 --- a/src/qmlcontrols/managedtexturenode.cpp +++ b/src/qmlcontrols/managedtexturenode.cpp @@ -1,29 +1,30 @@ /* * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "managedtexturenode.h" ManagedTextureNode::ManagedTextureNode() -{} +{ +} void ManagedTextureNode::setTexture(QSharedPointer texture) { m_texture = texture; QSGSimpleTextureNode::setTexture(texture.data()); } diff --git a/src/qmlcontrols/managedtexturenode.h b/src/qmlcontrols/managedtexturenode.h index f1658eb..4949a18 100644 --- a/src/qmlcontrols/managedtexturenode.h +++ b/src/qmlcontrols/managedtexturenode.h @@ -1,53 +1,53 @@ /* * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MANAGEDTEXTURENODE_H #define MANAGEDTEXTURENODE_H #include #include #include /** * @short Node that contains a reference counted texture * * Usually when assigning textures within a node, we'll want to delete the * texture with the node. This class will take a shared texture and display it * within the node. * * It's especially interesting to use this class together with the ImageTexturesCache * that will offer us shareable textures and cache them transparently, when asking * it to create the texture. * * @see ImageTexturesCache */ class ManagedTextureNode : public QSGSimpleTextureNode { -Q_DISABLE_COPY(ManagedTextureNode) + Q_DISABLE_COPY(ManagedTextureNode) public: ManagedTextureNode(); void setTexture(QSharedPointer texture); private: QSharedPointer m_texture; }; #endif diff --git a/src/ui/appearencedialogpage.cpp b/src/ui/appearencedialogpage.cpp index 03217a5..2a8ccc9 100644 --- a/src/ui/appearencedialogpage.cpp +++ b/src/ui/appearencedialogpage.cpp @@ -1,47 +1,45 @@ /* * Copyright 2013 Magdalena Konkiewicz * * 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 "appearencedialogpage.h" #include "settings.h" - AppearenceDialogPage::AppearenceDialogPage() : QWidget(nullptr) { ui = new Ui::AppearenceDialogPage; ui->setupUi(this); } AppearenceDialogPage::~AppearenceDialogPage() { delete ui; } void AppearenceDialogPage::loadSettings() { ui->kcfg_TrainingPhraseFont->setFont(Settings::trainingPhraseFont()); } void AppearenceDialogPage::saveSettings() { Settings::setTrainingPhraseFont(ui->kcfg_TrainingPhraseFont->font()); Settings::self()->save(); } - diff --git a/src/ui/appearencedialogpage.h b/src/ui/appearencedialogpage.h index 5c74663..b172d38 100644 --- a/src/ui/appearencedialogpage.h +++ b/src/ui/appearencedialogpage.h @@ -1,44 +1,43 @@ /* * Copyright 2013 Magdalena Konkiewicz * * 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 APPEARENCEDIALOGPAGE_H #define APPEARENCEDIALOGPAGE_H #include "ui_appearencedialogpage.h" #include -class AppearenceDialogPage : - public QWidget +class AppearenceDialogPage : public QWidget { Q_OBJECT public: AppearenceDialogPage(); ~AppearenceDialogPage(); public slots: void saveSettings(); void loadSettings(); private: Ui::AppearenceDialogPage *ui; }; #endif diff --git a/src/ui/exportghnsdialog.cpp b/src/ui/exportghnsdialog.cpp index fc44df8..cf4a4ba 100644 --- a/src/ui/exportghnsdialog.cpp +++ b/src/ui/exportghnsdialog.cpp @@ -1,85 +1,78 @@ /* * Copyright 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 "exportghnsdialog.h" +#include "artikulate_debug.h" +#include "core/icourse.h" #include "core/iresourcerepository.h" -#include "core/resources/editablecourseresource.h" -#include "core/resources/courseparser.h" #include "core/language.h" -#include "core/icourse.h" -#include "artikulate_debug.h" +#include "core/resources/courseparser.h" +#include "core/resources/editablecourseresource.h" #include #include #include #include #include ExportGhnsDialog::ExportGhnsDialog(IResourceRepository *repository) { ui = new Ui::ExportGhnsDialog; ui->setupUi(this); // require to set a proper directory ui->buttonBox->button(QDialogButtonBox::Apply)->setDisabled(true); ui->buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Export")); - connect(ui->exportDirectory, &QLineEdit::textChanged, this, [=](){ + connect(ui->exportDirectory, &QLineEdit::textChanged, this, [=]() { const bool directorySet = !ui->exportDirectory->text().isEmpty(); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(directorySet); }); - connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, - this, &ExportGhnsDialog::onExportCourse); + connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &ExportGhnsDialog::onExportCourse); // directory selection dialog connect(ui->selectDirectoryButton, &QToolButton::clicked, this, [=]() { // TODO save last path in config file - const QString dir = QFileDialog::getExistingDirectory( - this, - i18n("Export Directory"), - QString(), - QFileDialog::ShowDirsOnly); + const QString dir = QFileDialog::getExistingDirectory(this, i18n("Export Directory"), QString(), QFileDialog::ShowDirsOnly); ui->exportDirectory->setText(dir); }); // add courses to combo box int counter = 0; for (auto language : repository->languages()) { for (auto course : repository->courses(language->id())) { - ui->courseListCombo->insertItem(counter, course->i18nTitle(), - QVariant::fromValue(course.get())); + ui->courseListCombo->insertItem(counter, course->i18nTitle(), QVariant::fromValue(course.get())); ++counter; } } connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } ExportGhnsDialog::~ExportGhnsDialog() { delete ui; } void ExportGhnsDialog::onExportCourse() { - IEditableCourse *res = qobject_cast( - ui->courseListCombo->currentData().value()); + IEditableCourse *res = qobject_cast(ui->courseListCombo->currentData().value()); qCDebug(ARTIKULATE_LOG) << res << "export GHNS file for" << res->i18nTitle(); CourseParser::exportCourseToGhnsPackage(res->self(), ui->exportDirectory->text()); } diff --git a/src/ui/exportghnsdialog.h b/src/ui/exportghnsdialog.h index 76e86a2..78d930c 100644 --- a/src/ui/exportghnsdialog.h +++ b/src/ui/exportghnsdialog.h @@ -1,46 +1,45 @@ /* * Copyright 2013 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 EXPORTGHNSDIALOG_H #define EXPORTGHNSDIALOG_H #include "ui_exportghnsdialog.h" -#include #include +#include class IResourceRepository; -class ExportGhnsDialog : - public QDialog +class ExportGhnsDialog : public QDialog { Q_OBJECT public: explicit ExportGhnsDialog(IResourceRepository *repository); ~ExportGhnsDialog(); public Q_SLOTS: void onExportCourse(); private: Ui::ExportGhnsDialog *ui; }; #endif diff --git a/src/ui/sounddevicedialogpage.cpp b/src/ui/sounddevicedialogpage.cpp index 2eab4c7..9057c51 100644 --- a/src/ui/sounddevicedialogpage.cpp +++ b/src/ui/sounddevicedialogpage.cpp @@ -1,176 +1,174 @@ /* * Copyright 2013 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 "sounddevicedialogpage.h" #include "libsound/src/capturedevicecontroller.h" #include "libsound/src/outputdevicecontroller.h" #include "settings.h" #include #include SoundDeviceDialogPage::SoundDeviceDialogPage() : QWidget(nullptr) { ui = new Ui::SoundDeviceDialogPage; ui->setupUi(this); // set buttons ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); ui->buttonRecordTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-record"))); ui->buttonPlayRecordedTestSound->setEnabled(false); // set input volume slider - //TODO Qt5.x port: reenable, since that we can set audioinput volume -// ui->kcfg_AudioInputVolume->setTickInterval(1); -// ui->kcfg_AudioInputVolume->setMinimum(1); -// ui->kcfg_AudioInputVolume->setMaximum(100); + // TODO Qt5.x port: reenable, since that we can set audioinput volume + // ui->kcfg_AudioInputVolume->setTickInterval(1); + // ui->kcfg_AudioInputVolume->setMinimum(1); + // ui->kcfg_AudioInputVolume->setMaximum(100); // set output volume slider ui->kcfg_AudioOutputVolume->setTickInterval(0); ui->kcfg_AudioOutputVolume->setMinimum(0); ui->kcfg_AudioOutputVolume->setMaximum(20); // devices QStringList devices = CaptureDeviceController::self().devices(); - for (int i=0; i < devices.length(); ++i) { + for (int i = 0; i < devices.length(); ++i) { ui->kcfg_AudioInputDevice->insertItem(i, devices.at(i), i); } - //TODO Gst::Device will allow selecting devices again with GStreamer 1.4 + // TODO Gst::Device will allow selecting devices again with GStreamer 1.4 // temporary file for recording test m_recordTestFile.open(); // connections connect(ui->kcfg_AudioOutputVolume, &QAbstractSlider::valueChanged, this, &SoundDeviceDialogPage::setVolume); connect(ui->buttonPlayTestSound, &QAbstractButton::clicked, this, &SoundDeviceDialogPage::playTestSound); connect(ui->buttonPlayRecordedTestSound, &QAbstractButton::clicked, this, &SoundDeviceDialogPage::playRecordedSound); connect(ui->buttonRecordTestSound, &QAbstractButton::clicked, this, &SoundDeviceDialogPage::recordSound); connect(&OutputDeviceController::self(), &OutputDeviceController::started, this, &SoundDeviceDialogPage::updatePlayButtonIcons); connect(&OutputDeviceController::self(), &OutputDeviceController::stopped, this, &SoundDeviceDialogPage::updatePlayButtonIcons); } SoundDeviceDialogPage::~SoundDeviceDialogPage() { CaptureDeviceController::self().stopCapture(); CaptureDeviceController::self().setDevice(Settings::audioInputDevice()); delete ui; } void SoundDeviceDialogPage::loadSettings() { - ui->kcfg_AudioInputDevice->setCurrentIndex( - ui->kcfg_AudioInputDevice->findText(Settings::audioInputDevice())); -// ui->kcfg_AudioInputVolume->setValue(Settings::audioInputVolume()); + ui->kcfg_AudioInputDevice->setCurrentIndex(ui->kcfg_AudioInputDevice->findText(Settings::audioInputDevice())); + // ui->kcfg_AudioInputVolume->setValue(Settings::audioInputVolume()); ui->kcfg_AudioOutputVolume->setValue(Settings::audioOutputVolume()); } void SoundDeviceDialogPage::setVolume(int volume) { OutputDeviceController::self().setVolume(volume); } void SoundDeviceDialogPage::saveSettings() { Settings::setAudioInputDevice(ui->kcfg_AudioInputDevice->itemText(ui->kcfg_AudioInputDevice->currentIndex())); -// Settings::setAudioInputVolume(ui->kcfg_AudioInputVolume->value()); + // Settings::setAudioInputVolume(ui->kcfg_AudioInputVolume->value()); Settings::setAudioOutputVolume(static_cast(ui->kcfg_AudioOutputVolume->value())); OutputDeviceController::self().setVolume(ui->kcfg_AudioOutputVolume->value()); Settings::self()->save(); } void SoundDeviceDialogPage::playTestSound() { if (OutputDeviceController::self().state() == OutputDeviceController::PlayingState) { OutputDeviceController::self().stop(); return; } QString testsoundFile = QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("sounds/testsound.ogg")); OutputDeviceController::self().setVolume(ui->kcfg_AudioOutputVolume->value()); OutputDeviceController::self().play(QUrl::fromLocalFile(testsoundFile)); } void SoundDeviceDialogPage::playRecordedSound() { if (OutputDeviceController::self().state() == OutputDeviceController::PlayingState) { OutputDeviceController::self().stop(); return; } OutputDeviceController::self().setVolume(ui->kcfg_AudioOutputVolume->value()); OutputDeviceController::self().play(QUrl::fromLocalFile(m_recordTestFile.fileName())); } void SoundDeviceDialogPage::stopPlaying() { OutputDeviceController::self().stop(); } void SoundDeviceDialogPage::recordSound() { - if (CaptureDeviceController::self().state() == CaptureDeviceController::RecordingState) - { + if (CaptureDeviceController::self().state() == CaptureDeviceController::RecordingState) { CaptureDeviceController::self().stopCapture(); ui->buttonRecordTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-record"))); ui->buttonPlayRecordedTestSound->setEnabled(true); return; } ui->buttonRecordTestSound->setIcon(QIcon::fromTheme(QStringLiteral("artikulate-media-record-active"))); CaptureDeviceController::self().setDevice(ui->kcfg_AudioInputDevice->currentText()); CaptureDeviceController::self().startCapture(m_recordTestFile.fileName()); } void SoundDeviceDialogPage::stopRecord() { if (CaptureDeviceController::self().state() == CaptureDeviceController::RecordingState) { CaptureDeviceController::self().stopCapture(); ui->buttonRecordTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-record"))); ui->buttonPlayRecordedTestSound->setEnabled(true); } } void SoundDeviceDialogPage::updatePlayButtonIcons() { // default sound output test switch (OutputDeviceController::self().state()) { - case OutputDeviceController::PlayingState: - ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); - break; - case OutputDeviceController::StoppedState: - ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); - break; - default: - ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); + case OutputDeviceController::PlayingState: + ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); + break; + case OutputDeviceController::StoppedState: + ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); + break; + default: + ui->buttonPlayTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); } // recorded sound output test switch (OutputDeviceController::self().state()) { - case OutputDeviceController::PlayingState: - ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); - break; - case OutputDeviceController::StoppedState: - ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); - break; - default: - ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); + case OutputDeviceController::PlayingState: + ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); + break; + case OutputDeviceController::StoppedState: + ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); + break; + default: + ui->buttonPlayRecordedTestSound->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); } } diff --git a/src/ui/sounddevicedialogpage.h b/src/ui/sounddevicedialogpage.h index e2f86bb..a03a1e3 100644 --- a/src/ui/sounddevicedialogpage.h +++ b/src/ui/sounddevicedialogpage.h @@ -1,56 +1,54 @@ /* * Copyright 2013 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 SOUNDDEVICEDIALOGPAGE_H #define SOUNDDEVICEDIALOGPAGE_H #include "ui_sounddevicedialogpage.h" #include #include - -class SoundDeviceDialogPage : - public QWidget +class SoundDeviceDialogPage : public QWidget { Q_OBJECT public: SoundDeviceDialogPage(); ~SoundDeviceDialogPage(); public slots: void saveSettings(); void loadSettings(); void playTestSound(); void playRecordedSound(); void recordSound(); void updatePlayButtonIcons(); void stopPlaying(); void stopRecord(); void setVolume(int volume); private: Ui::SoundDeviceDialogPage *ui; QList m_audioInputs; QList m_audioOutputs; QTemporaryFile m_recordTestFile; }; #endif