diff --git a/autotests/testlanguagefiles.cpp b/autotests/testlanguagefiles.cpp index 63be8d0..06a9375 100644 --- a/autotests/testlanguagefiles.cpp +++ b/autotests/testlanguagefiles.cpp @@ -1,137 +1,131 @@ /* * 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/resourcemanager.h" #include "core/language.h" #include "core/unit.h" #include "core/phrase.h" #include #include #include #include #include #include #include #include #include #include TestLanguageFiles::TestLanguageFiles() { - //FIXME port this -// KGlobal::dirs()->addResourceDir("appdata" , "./autotests/data"); -// KGlobal::dirs()->addResourceDir("appdata" , "./autotests"); -// KGlobal::dirs()->addResourceDir("appdata" , "./"); } void TestLanguageFiles::init() { // TODO initialization of test case } void TestLanguageFiles::cleanup() { // TODO cleanup after test run } QXmlSchema TestLanguageFiles::loadXmlSchema(const QString &schemeName) const { QString relPath = QStringLiteral("schemes/%1.xsd").arg(schemeName); QUrl file = QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::DataLocation, relPath)); QXmlSchema schema; if (schema.load(file) == false) { qWarning() << "Schema at file " << file.toLocalFile() << " is invalid."; } return schema; } QDomDocument TestLanguageFiles::loadDomDocument(const QUrl &path, const QXmlSchema &schema) const { QDomDocument document; QXmlSchemaValidator validator(schema); if (!validator.validate(path)) { qWarning() << "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)) { qWarning() << errorMsg; } } else { qWarning() << "Could not open XML document " << path.toLocalFile() << " for reading, aborting."; } return document; } void TestLanguageFiles::languageSchemeValidationTest() { QUrl languageFile = QUrl::fromLocalFile(QStringLiteral("schemes/language.xsd")); QXmlSchema languageSchema; QVERIFY(languageSchema.load(languageFile)); QVERIFY(languageSchema.isValid()); } void TestLanguageFiles::checkIdUniqueness() { - ResourceManager manager; QStringList languageFiles = QStandardPaths::locateAll(QStandardPaths::DataLocation, QStringLiteral("data/languages/*.xml")); foreach (const QString &file, languageFiles) { qDebug() << "File being parsed: " << file; QStringList idList; const QUrl &languageFile = QUrl::fromLocalFile(file); QVERIFY(languageFile.isLocalFile()); QXmlSchema schema = loadXmlSchema(QStringLiteral("language")); QVERIFY(schema.isValid()); QDomDocument document = loadDomDocument(languageFile, schema); QVERIFY(!document.isNull()); QDomElement root(document.documentElement()); Language *language = new Language(this); language->setFile(languageFile); language->setId(root.firstChildElement(QStringLiteral("id")).text()); language->setTitle(root.firstChildElement(QStringLiteral("title")).text()); // create phoneme groups for (QDomElement groupNode = root.firstChildElement(QStringLiteral("phonemeGroups")).firstChildElement(); !groupNode.isNull(); groupNode = groupNode.nextSiblingElement()) { for (QDomElement phonemeNode = groupNode.firstChildElement(QStringLiteral("phonemes")).firstChildElement(); !phonemeNode.isNull(); phonemeNode = phonemeNode.nextSiblingElement()) { QString id = phonemeNode.firstChildElement(QStringLiteral("id")).text(); qDebug() << "ID: " << id; QVERIFY2(!idList.contains(id),"Phoneme ID used more than once in the tested file"); idList.append(id); } } } } QTEST_GUILESS_MAIN(TestLanguageFiles) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 83e9f45..166574b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,201 +1,202 @@ ### # Copyright 2013-2015 Andreas Cord-Landwehr # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### ecm_setup_version(0.99.90 VARIABLE_PREFIX ARTIKULATE VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/ArtikulateConfigVersion.cmake" ) ecm_optional_add_subdirectory(qml) # set include directories include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${artikulate_SOURCE_DIR} ) # set the source code files from which Artikulate is compiled set(artikulateCore_SRCS core/icourse.h core/drawertrainingactions.cpp - core/resourcemanager.cpp core/iresourcerepository.h core/resourcerepository.cpp + core/contributorrepository.cpp core/language.cpp core/phrase.cpp core/phoneme.cpp core/phonemegroup.cpp core/unit.cpp core/skeleton.cpp core/editorsession.cpp core/trainingaction.cpp core/trainingactionicon.cpp core/trainingsession.cpp core/resources/resourceinterface.cpp core/resources/languageresource.cpp core/resources/courseparser.cpp core/resources/courseresource.cpp core/resources/editablecourseresource.cpp core/resources/skeletonresource.cpp core/player.cpp core/recorder.cpp qmlcontrols/iconitem.cpp qmlcontrols/imagetexturescache.cpp qmlcontrols/managedtexturenode.cpp artikulate_debug.cpp ) kconfig_add_kcfg_files (artikulateCore_SRCS settings.kcfgc) add_library(artikulatecore SHARED ${artikulateCore_SRCS}) generate_export_header(artikulatecore BASE_NAME artikulatecore) target_link_libraries(artikulatecore LINK_PUBLIC artikulatelearnerprofile artikulatesound Qt5::XmlPatterns Qt5::Quick KF5::Archive KF5::ConfigGui ) # internal library without any API or ABI guarantee set(GENERIC_LIB_VERSION "0") set(GENERIC_LIB_SOVERSION "0") set_target_properties( artikulatecore PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install( TARGETS artikulatecore DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS} ) install(FILES artikulate.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) # set the source code files from which Artikulate is compiled set(artikulate_SRCS main.cpp mainwindow.cpp application.cpp artikulate_debug.cpp models/coursemodel.cpp models/coursefiltermodel.cpp models/languagemodel.cpp models/languageresourcemodel.cpp # models/learningprogressmodel.cpp //TODO must be adapted to new trainingsession models/unitmodel.cpp models/unitfiltermodel.cpp models/phrasemodel.cpp models/phraselistmodel.cpp models/phrasefiltermodel.cpp models/phonememodel.cpp models/phonemegroupmodel.cpp models/phonemeunitmodel.cpp models/profilemodel.cpp models/skeletonmodel.cpp ui/sounddevicedialogpage.cpp ui/appearencedialogpage.cpp ui/resourcesdialogpage.cpp ) ki18n_wrap_ui (artikulate_SRCS ui/resourcesdialogpage.ui ui/sounddevicedialogpage.ui ui/appearencedialogpage.ui ) qt5_add_resources(artikulate_SRCS resources.qrc) qt5_add_resources(artikulate_SRCS ../data/languages.qrc) kconfig_add_kcfg_files (artikulate_SRCS settings.kcfgc) set(artikulate_editor_SRCS main_editor.cpp mainwindow_editor.cpp application.cpp artikulate_debug.cpp models/coursemodel.cpp models/coursefiltermodel.cpp models/languagemodel.cpp models/languageresourcemodel.cpp # models/learningprogressmodel.cpp //TODO must be adapted to new trainingsession models/unitmodel.cpp models/unitfiltermodel.cpp models/phrasemodel.cpp models/phraselistmodel.cpp models/phrasefiltermodel.cpp models/phonememodel.cpp models/phonemegroupmodel.cpp models/phonemeunitmodel.cpp models/profilemodel.cpp models/skeletonmodel.cpp ui/sounddevicedialogpage.cpp ui/appearencedialogpage.cpp ui/resourcesdialogpage.cpp ui/exportghnsdialog.cpp ) ki18n_wrap_ui(artikulate_editor_SRCS ui/appearencedialogpage.ui ui/exportghnsdialog.ui ui/resourcesdialogpage.ui ui/sounddevicedialogpage.ui ) qt5_add_resources(artikulate_editor_SRCS resources.qrc) +qt5_add_resources(artikulate_editor_SRCS ../data/languages.qrc) kconfig_add_kcfg_files (artikulate_editor_SRCS settings.kcfgc) # executables add_executable(artikulate ${artikulate_SRCS}) target_link_libraries(artikulate LINK_PUBLIC artikulatelearnerprofile artikulatesound artikulatecore Qt5::Qml Qt5::Quick KF5::Crash KF5::NewStuff KF5::XmlGui ) qt5_add_resources(artikulate_editor_SRCS editor.qrc) add_executable(artikulate_editor ${artikulate_editor_SRCS}) target_link_libraries(artikulate_editor LINK_PUBLIC artikulatesound artikulatecore Qt5::Qml Qt5::Quick Qt5::QuickWidgets KF5::Crash KF5::NewStuff KF5::XmlGui ) install(FILES artikulate.kcfg DESTINATION ${KCFG_INSTALL_DIR}) install(TARGETS artikulate ${INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS artikulate_editor ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/application.cpp b/src/application.cpp index 9d36e76..941925c 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,137 +1,141 @@ /* * 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/iresourcerepository.h" +#include "core/contributorrepository.h" #include "core/drawertrainingactions.h" #include "core/trainingaction.h" #include "core/editorsession.h" #include "core/language.h" #include "core/phoneme.h" #include "core/phonemegroup.h" #include "core/phrase.h" #include "core/player.h" #include "core/recorder.h" -#include "core/resourcemanager.h" #include "core/skeleton.h" #include "core/trainingsession.h" #include "core/unit.h" +#include "core/resources/editablecourseresource.h" #include "models/coursefiltermodel.h" #include "models/coursemodel.h" #include "models/languagemodel.h" #include "models/languageresourcemodel.h" #include "models/learningprogressmodel.h" #include "models/phonemegroupmodel.h" #include "models/phonememodel.h" #include "models/phonemeunitmodel.h" #include "models/phrasefiltermodel.h" #include "models/phraselistmodel.h" #include "models/phrasemodel.h" #include "models/profilemodel.h" #include "models/skeletonmodel.h" #include "models/unitfiltermodel.h" #include "models/unitmodel.h" #include "qmlcontrols/iconitem.h" #include "liblearnerprofile/src/learner.h" #include "liblearnerprofile/src/profilemanager.h" #include "liblearnerprofile/src/learninggoal.h" #include "liblearnerprofile/src/models/learninggoalmodel.h" #include #include #include #include #include Application::Application(int& argc, char** argv) : QApplication(argc, argv) { registerQmlTypes(); } IResourceRepository * Application::resourceRepository() const { return 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( + qmlRegisterUncreatableType( "artikulate", 1, 0, - "ResourceManager", - QStringLiteral("ResourceManager is unique object provided by the backend")); + "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")); // interfaces qmlRegisterInterface("IResourceRepository"); qmlRegisterInterface("ICourse"); // concrete instantiable types qmlRegisterType("artikulate", 1, 0, "Learner"); qmlRegisterType("artikulate", 1, 0, "LearningGoal"); qmlRegisterType("artikulate", 1, 0, "Unit"); qmlRegisterType("artikulate", 1, 0, "Skeleton"); qmlRegisterType("artikulate", 1, 0, "Language"); - qmlRegisterType("artikulate", 1, 0, "ResourceManager"); qmlRegisterType("artikulate", 1, 0, "Phrase"); qmlRegisterType("artikulate", 1, 0, "Phoneme"); qmlRegisterType("artikulate", 1, 0, "PhonemeGroup"); qmlRegisterType("artikulate", 1, 0, "Player"); qmlRegisterType("artikulate", 1, 0, "Recorder"); qmlRegisterType("artikulate", 1, 0, "Icon"); qmlRegisterType("artikulate", 1, 0, "DrawerTrainingActions"); qmlRegisterType("artikulate", 1, 0, "TrainingAction"); // models qmlRegisterType("artikulate", 1, 0, "CourseModel"); qmlRegisterType("artikulate", 1, 0, "CourseFilterModel"); qmlRegisterType("artikulate", 1, 0, "LanguageModel"); qmlRegisterType("artikulate", 1, 0, "LanguageResourceModel"); // qmlRegisterType("artikulate", 1, 0, "LearningProgressModel");//TODO must be ported to new trainingsession qmlRegisterType("artikulate", 1, 0, "UnitModel"); qmlRegisterType("artikulate", 1, 0, "UnitFilterModel"); qmlRegisterType("artikulate", 1, 0, "PhraseModel"); qmlRegisterType("artikulate", 1, 0, "PhraseListModel"); qmlRegisterType("artikulate", 1, 0, "PhraseFilterModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeGroupModel"); qmlRegisterType("artikulate", 1, 0, "PhonemeUnitModel"); qmlRegisterType("artikulate", 1, 0, "ProfileModel"); qmlRegisterType("artikulate", 1, 0, "SkeletonModel"); qmlRegisterType("artikulate", 1, 0, "LearningGoalModel"); } diff --git a/src/core/resourcemanager.cpp b/src/core/contributorrepository.cpp similarity index 82% rename from src/core/resourcemanager.cpp rename to src/core/contributorrepository.cpp index 0d63921..e826ba5 100644 --- a/src/core/resourcemanager.cpp +++ b/src/core/contributorrepository.cpp @@ -1,467 +1,484 @@ /* - * Copyright 2013-2015 Andreas Cord-Landwehr + * Copyright 2013-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "resourcemanager.h" +#include "contributorrepository.h" #include "language.h" #include "skeleton.h" #include "unit.h" #include "phrase.h" #include "phoneme.h" #include "phonemegroup.h" #include "resources/languageresource.h" #include "resources/editablecourseresource.h" #include "resources/skeletonresource.h" #include "settings.h" #include "liblearnerprofile/src/profilemanager.h" #include "liblearnerprofile/src/learninggoal.h" #include #include #include #include #include #include #include #include #include #include "artikulate_debug.h" #include #include -ResourceManager::ResourceManager(QObject *parent) - : QObject(parent) +ContributorRepository::ContributorRepository(QObject *parent) + : IResourceRepository() { } -void ResourceManager::loadCourseResources() +void ContributorRepository::loadCourseResources() { //TODO fix this method such that it may be called many times of e.g. updating // reload config, could be changed in dialogs Settings::self()->load(); // register skeleton resources QDir skeletonRepository = QDir(Settings::courseRepositoryPath()); skeletonRepository.setFilter(QDir::Files | QDir::Hidden); if (!skeletonRepository.cd(QStringLiteral("skeletons"))) { qCritical() << "There is no subdirectory \"skeletons\" in directory " << skeletonRepository.path() << " cannot load skeletons."; } else { // read skeletons QFileInfoList list = skeletonRepository.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); addSkeleton(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); } } // register contributor course files QDir courseRepository = QDir(Settings::courseRepositoryPath()); if (!courseRepository.cd(QStringLiteral("courses"))) { qCritical() << "There is no subdirectory \"courses\" in directory " << courseRepository.path() << " cannot load courses."; } else { // find courses courseRepository.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList courseDirList = courseRepository.entryInfoList(); // traverse all course directories foreach (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 foreach (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 foreach (const QFileInfo &courseInfo, courses) { addCourse(QUrl::fromLocalFile(courseInfo.filePath())); } } } } // register GHNS course resources QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::DataLocation); foreach (const QString &testdir, dirs) { QDirIterator it(testdir + "/courses/", QDirIterator::Subdirectories); while (it.hasNext()) { QDir dir(it.next()); 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; } addCourse(QUrl::fromLocalFile(fileInfo.absoluteFilePath())); } } } //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 ResourceManager::loadLanguageResources() +void ContributorRepository::loadLanguageResources() { // load language resources // all other resources are only loaded on demand - QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); - foreach (const QString &testdir, dirs) { - QDir dir(testdir + "/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())); + 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 ResourceManager::sync() +void ContributorRepository::sync() { // QMap< QString, QList< CourseResource* > >::iterator iter; // for (iter = m_courseResources.begin(); iter != m_courseResources.end(); ++iter) { // foreach (auto const &courseRes, iter.value()) { // courseRes->sync(); // } // } // foreach (auto const &courseRes, m_skeletonResources) { // courseRes->sync(); // } } -bool ResourceManager::modified() const +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; } } } foreach (auto const &courseRes, m_skeletonResources) { if (courseRes->isOpen() && courseRes->skeleton()->isModified()) { return true; } } return false; } -void ResourceManager::addLanguage(const QUrl &languageFile) +void ContributorRepository::addLanguage(const QUrl &languageFile) { if (m_loadedResources.contains(languageFile.toLocalFile())) { return; } - LanguageResource *resource = new LanguageResource(this, languageFile); + LanguageResource *resource = new LanguageResource(languageFile); emit languageResourceAboutToBeAdded(resource, m_languageResources.count()); m_languageResources.append(resource); m_loadedResources.append(languageFile.toLocalFile()); m_courses.insert(resource->identifier(), QList()); emit languageResourceAdded(); } -bool ResourceManager::isRepositoryManager() const +bool ContributorRepository::isRepositoryManager() const { return !Settings::courseRepositoryPath().isEmpty(); } -QString ResourceManager::repositoryUrl() const +QString ContributorRepository::storageLocation() const { return Settings::courseRepositoryPath(); } -QList< LanguageResource* > ResourceManager::languageResources() const +QList< LanguageResource* > ContributorRepository::languageResources() const { return m_languageResources; } -Language * ResourceManager::language(int index) const +QVector ContributorRepository::languages() const +{ + QVector languages; + for (auto resourse : m_languageResources) { + languages.append(resourse->language()); + } + return languages; +} + +Language * ContributorRepository::language(int index) const { Q_ASSERT(index >= 0 && index < m_languageResources.count()); return m_languageResources.at(index)->language(); } -Language * ResourceManager::language(LearnerProfile::LearningGoal *learningGoal) const +Language * 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; } foreach (LanguageResource *resource, m_languageResources) { if (resource->identifier() == learningGoal->identifier()) { return resource->language(); } } qCritical() << "No language registered with identifier " << learningGoal->identifier() << ": aborting"; return nullptr; } -QList ResourceManager::courseResources(Language *language) +QList ContributorRepository::courseResources(Language *language) { if (!language) { QList 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 QList< EditableCourseResource* >(); } return m_courses[language->id()]; } -EditableCourseResource * ResourceManager::course(Language *language, int index) const +QVector ContributorRepository::courses() const +{ + return QVector(); //TODO and check if overload for editable is needed +} + +QVector ContributorRepository::courses(Language *language) const +{ + return QVector(); //TODO and check if overload for editable is needed +} + +EditableCourseResource * ContributorRepository::course(Language *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 ResourceManager::reloadCourseOrSkeleton(ICourse *courseOrSkeleton) +void ContributorRepository::reloadCourseOrSkeleton(ICourse *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 // to catch possible errors QUrl file = courseOrSkeleton->file(); m_loadedResources.removeOne(courseOrSkeleton->file().toLocalFile()); removeCourse(courseOrSkeleton); addCourse(file); } else { foreach (SkeletonResource *resource, m_skeletonResources) { if (resource->identifier() == courseOrSkeleton->id()) { resource->reload(); return; } } } } -void ResourceManager::updateCourseFromSkeleton(EditableCourseResource *course) +void ContributorRepository::updateCourseFromSkeleton(EditableCourseResource *course) { //TODO implement status information that are shown at mainwindow if (course->foreignId().isEmpty()) { qCritical() << "No skeleton ID specified, aborting update."; return; } ICourse *skeleton = nullptr; QList::ConstIterator iter = m_skeletonResources.constBegin(); while (iter != m_skeletonResources.constEnd()) { if ((*iter)->identifier() == course->foreignId()) { skeleton = (*iter)->skeleton(); break; } ++iter; } if (!skeleton) { qCritical() << "Could not find skeleton with id " << course->foreignId() << ", aborting update."; return; } // update now foreach (Unit *unitSkeleton, skeleton->unitList()) { // import unit if not exists Unit *currentUnit = nullptr; bool found = false; foreach (Unit *unit, course->unitList()) { if (unit->foreignId() == unitSkeleton->id()) { found = true; currentUnit = unit; break; } } if (found == false) { currentUnit = new Unit(course); currentUnit->setId(QUuid::createUuid().toString()); currentUnit->setTitle(unitSkeleton->title()); currentUnit->setForeignId(unitSkeleton->id()); currentUnit->setCourse(course); course->addUnit(currentUnit); course->setModified(true); } // update phrases foreach (Phrase *phraseSkeleton, unitSkeleton->phraseList()) { bool found = false; foreach (Phrase *phrase, currentUnit->phraseList()) { if (phrase->foreignId() == phraseSkeleton->id()) { if (phrase->i18nText() != phraseSkeleton->text()) { phrase->setEditState(Phrase::Unknown); phrase->seti18nText(phraseSkeleton->text()); } found = true; break; } } if (found == false) { Phrase *newPhrase = new Phrase(course); newPhrase->setForeignId(phraseSkeleton->id()); newPhrase->setId(QUuid::createUuid().toString()); newPhrase->setText(phraseSkeleton->text()); newPhrase->seti18nText(phraseSkeleton->text()); newPhrase->setType(phraseSkeleton->type()); newPhrase->setUnit(currentUnit); currentUnit->addPhrase(newPhrase); course->setModified(true); } } } // FIXME deassociate removed phrases qCDebug(ARTIKULATE_LOG) << "Update performed!"; } -EditableCourseResource * ResourceManager::addCourse(const QUrl &courseFile) +EditableCourseResource * ContributorRepository::addCourse(const QUrl &courseFile) { - EditableCourseResource *resource = new EditableCourseResource(courseFile, nullptr); //FIXME second parameter must be interface! + EditableCourseResource *resource = new EditableCourseResource(courseFile, this); if (resource->language() == nullptr) { delete resource; qCritical() << "Could not load course, language unknown:" << courseFile.toLocalFile(); return nullptr; } // skip already loaded resources if (m_loadedResources.contains(courseFile.toLocalFile())) { delete resource; return nullptr; } m_loadedResources.append(courseFile.toLocalFile()); addCourseResource(resource); emit languageCoursesChanged(); return resource; } -void ResourceManager::addCourseResource(EditableCourseResource *resource) +void ContributorRepository::addCourseResource(EditableCourseResource *resource) { Q_ASSERT(m_courses.contains(resource->language()->id())); if (m_courses.contains(resource->language()->id())) { // emit courseResourceAboutToBeAdded(resource, m_courses[resource->language()].count()); //FIXME } else { - emit courseResourceAboutToBeAdded(resource, 0); + emit courseAboutToBeAdded(resource, 0); m_courses.insert(resource->language()->id(), QList()); } m_courses[resource->language()->id()].append(resource); - emit courseResourceAdded(); + emit courseAdded(); } -void ResourceManager::removeCourse(ICourse *course) +void ContributorRepository::removeCourse(ICourse *course) { for (int index = 0; index < m_courses[course->language()->id()].length(); ++index) { if (m_courses[course->language()->id()].at(index) == course) { - emit courseResourceAboutToBeRemoved(index); + emit courseAboutToBeRemoved(index); m_courses[course->language()->id()].removeAt(index); + emit courseRemoved(); course->deleteLater(); return; } } } -EditableCourseResource * ResourceManager::createCourse(Language *language, Skeleton *skeleton) +EditableCourseResource * ContributorRepository::createCourse(Language *language, Skeleton *skeleton) { // set path QString path = QStringLiteral("%1/%2/%3/%4/%4.xml") .arg(Settings::courseRepositoryPath(), QStringLiteral("courses"), skeleton->id(), language->id()); - EditableCourseResource * course = new EditableCourseResource(QUrl::fromLocalFile(path), nullptr); //FIXME + EditableCourseResource * course = new EditableCourseResource(QUrl::fromLocalFile(path), this); Q_ASSERT(course); course->setId(QUuid::createUuid().toString()); course->setTitle(skeleton->title()); course->setDescription(skeleton->description()); course->setFile(QUrl::fromLocalFile(path)); course->setLanguage(language); // set skeleton course->setForeignId(skeleton->id()); addCourseResource(course); return course; } -void ResourceManager::addSkeleton(const QUrl &skeletonFile) +void ContributorRepository::addSkeleton(const QUrl &skeletonFile) { - SkeletonResource *resource = new SkeletonResource(this, skeletonFile); + SkeletonResource *resource = new SkeletonResource(skeletonFile); addSkeletonResource(resource); } -void ResourceManager::addSkeletonResource(SkeletonResource *resource) +void ContributorRepository::addSkeletonResource(SkeletonResource *resource) { // skip already loaded resources if (m_loadedResources.contains(resource->path().toLocalFile())) { return; } m_loadedResources.append(resource->path().toLocalFile()); emit skeletonAboutToBeAdded(resource->skeleton(), m_skeletonResources.count()); m_skeletonResources.append(resource); emit skeletonAdded(); } -void ResourceManager::removeSkeleton(Skeleton *skeleton) +void ContributorRepository::removeSkeleton(Skeleton *skeleton) { for (int index = 0; index < m_skeletonResources.length(); ++index) { if (m_skeletonResources.at(index)->identifier() == skeleton->id()) { emit skeletonAboutToBeRemoved(index, index); m_skeletonResources.removeAt(index); emit skeletonRemoved(); skeleton->deleteLater(); return; } } } -QList< SkeletonResource* > ResourceManager::skeletonResources() +QList< SkeletonResource* > ContributorRepository::skeletonResources() { return m_skeletonResources; } diff --git a/src/core/resourcemanager.h b/src/core/contributorrepository.h similarity index 84% rename from src/core/resourcemanager.h rename to src/core/contributorrepository.h index bc0ad71..0d4b9ae 100644 --- a/src/core/resourcemanager.h +++ b/src/core/contributorrepository.h @@ -1,216 +1,230 @@ /* - * Copyright 2013-2015 Andreas Cord-Landwehr + * Copyright 2013-2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef RESOURCEMANAGER_H -#define RESOURCEMANAGER_H +#ifndef CONTRIBUTORREPOSITORY_H +#define CONTRIBUTORREPOSITORY_H #include "artikulatecore_export.h" +#include "iresourcerepository.h" #include #include #include #include #include "liblearnerprofile/src/learninggoal.h" class SkeletonResource; class EditableCourseResource; class LanguageResource; class Skeleton; class Language; class ICourse; class ProfileManager; class QUrl; namespace LearnerProfile { class ProfileManager; } /** - * \class ResourceManager - * This class loads and stores all data files of the application. + * @class ContributorRepository + * This class handles the resources of a contributor. */ -class ARTIKULATECORE_EXPORT ResourceManager : public QObject +class ARTIKULATECORE_EXPORT ContributorRepository : public IResourceRepository { Q_OBJECT - Q_PROPERTY(bool isRepositoryManager READ isRepositoryManager NOTIFY repositoryChanged) - Q_PROPERTY(QString repositoryUrl READ repositoryUrl NOTIFY repositoryChanged) + Q_INTERFACES(IResourceRepository) + + Q_PROPERTY(QString repositoryUrl READ storageLocation NOTIFY repositoryChanged) public: - explicit ResourceManager(QObject *parent = nullptr); + explicit ContributorRepository(QObject *parent = nullptr); /** * Load all course resources. * This loading is very fast, since course files are only partly (~20 top lines) parsed and * the complete parsing is postponed until first access. * * This method is safe to be called several times for incremental updates. */ Q_INVOKABLE void loadCourseResources(); /** * This method loads all language files that are provided in the standard directories * for this application. */ void loadLanguageResources(); /** * 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 \c true if a repository is used, else \c false */ Q_INVOKABLE bool isRepositoryManager() const; /** * \return path to working repository, if one is set */ - QString repositoryUrl() const; + QString storageLocation() const override; /** * \return list of all available language specifications */ - QList languageResources() const; + Q_DECL_DEPRECATED QList languageResources() const; + + /** + * \return list of all available language specifications + */ + QVector languages() const; /** * \return language by \p index */ Q_INVOKABLE Language * language(int index) const; /** * \return language by \p learningGoal */ Q_INVOKABLE Language * language(LearnerProfile::LearningGoal* learningGoal) const; + QVector courses() const override; + QVector courses(Language *language) const override; + /** * \return list of all loaded courses for language \p language */ QList courseResources(Language *language); Q_INVOKABLE EditableCourseResource * course(Language *language, int index) const; /** * Reset the file for this course or skeleton. * * \param course the course to be reloaded */ Q_INVOKABLE void reloadCourseOrSkeleton(ICourse *course); + //TODO implement some logic + void reloadCourses() override {} + /** * Imports units and phrases from skeleton, deassociates removed ones. * * \param course the course to be update */ void updateCourseFromSkeleton(EditableCourseResource *course); /** * 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 */ EditableCourseResource * 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 */ void addCourseResource(EditableCourseResource *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(ICourse *course); /** * Create new course for \p language and derived from \p skeleton. * * \return created course */ Q_INVOKABLE EditableCourseResource * createCourse(Language *language, Skeleton *skeleton); /** * Adds skeleton resource to resource manager * * \param resource the skeleton resource to add to resource manager */ void addSkeleton(const QUrl &skeletonFile); /** * Adds skeleton resource to resource manager * * \param resource the skeleton resource to add to resource manager */ void addSkeletonResource(SkeletonResource *resource); /** * 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(Skeleton *skeleton); /** * \return list of all loaded skeletons resources */ QList skeletonResources(); Q_SIGNALS: void languageResourceAdded(); void languageResourceAboutToBeAdded(LanguageResource*,int); void languageResourceRemoved(); void languageResourceAboutToBeRemoved(int); void repositoryChanged(); - void courseResourceAdded(); - void courseResourceAboutToBeAdded(ICourse*,int); - void courseResourceAboutToBeRemoved(int); + void courseAdded() override; + void courseAboutToBeAdded(ICourse*,int) override; + void courseAboutToBeRemoved(int) override; + void courseRemoved() override; void skeletonAdded(); void skeletonAboutToBeAdded(ICourse*,int); void skeletonRemoved(); void skeletonAboutToBeRemoved(int,int); void languageCoursesChanged(); private: QList m_languageResources; QMap > m_courses; //!> (language-id, course-resource) QList m_skeletonResources; QStringList m_loadedResources; }; -#endif // RESOURCEMANAGER_H +#endif diff --git a/src/core/editorsession.cpp b/src/core/editorsession.cpp index 520f543..e91a634 100644 --- a/src/core/editorsession.cpp +++ b/src/core/editorsession.cpp @@ -1,278 +1,278 @@ /* * 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 "core/skeleton.h" #include "core/language.h" #include "core/resources/editablecourseresource.h" #include "core/resources/languageresource.h" #include "core/unit.h" #include "core/phrase.h" -#include "core/resourcemanager.h" +#include "core/contributorrepository.h" #include "artikulate_debug.h" EditorSession::EditorSession(QObject *parent) : QObject(parent) - , m_resourceManager(nullptr) + , m_repository(nullptr) , m_skeletonMode(true) , m_editSkeleton(false) , m_skeleton(nullptr) , m_language(nullptr) , m_course(nullptr) , m_tmpCourseWhileSkeletonEditing(nullptr) , m_unit(nullptr) , m_phrase(nullptr) { } -void EditorSession::setResourceManager(ResourceManager *manager) +void EditorSession::setContributorRepository(ContributorRepository *repository) { - m_resourceManager = manager; + m_repository = repository; } void EditorSession::setSkeletonMode(bool enabled) { if (m_skeletonMode == enabled) { return; } m_skeletonMode = enabled; emit skeletonModeChanged(); } bool EditorSession::skeletonMode() const { return m_skeletonMode; } void EditorSession::setEditSkeleton(bool enabled) { if (m_editSkeleton == enabled) { return; } m_editSkeleton = enabled; if (enabled) { m_tmpCourseWhileSkeletonEditing = m_course; // setCourse(m_skeleton); //FIXME port skeleton for this } else { setCourse(m_tmpCourseWhileSkeletonEditing); m_tmpCourseWhileSkeletonEditing = nullptr; } emit editSkeletonChanged(); } bool EditorSession::isEditSkeleton() const { return m_editSkeleton; } Skeleton * EditorSession::skeleton() const { return m_skeleton; } void EditorSession::setSkeleton(Skeleton *skeleton) { if (m_skeleton == skeleton) { return; } m_skeleton = skeleton; Language *language = m_language; if (!m_language) { - language = m_resourceManager->languageResources().constFirst()->language(); + language = m_repository->languages().constFirst(); } if (m_skeleton) { bool found = false; - int resources = m_resourceManager->courseResources(language).count(); + int resources = m_repository->courseResources(language).count(); for (int i=0; i < resources; ++i) { - EditableCourseResource * course = m_resourceManager->course(language, i); + EditableCourseResource * course = m_repository->course(language, i); if (course->foreignId() == m_skeleton->id()) { setCourse(course); found = true; break; } } if (!found) { setCourse(nullptr); } } emit skeletonChanged(); } Language * EditorSession::language() const { return m_language; } void EditorSession::setLanguage(Language *language) { if (m_language == language) { return; } m_language = language; if (m_skeletonMode) { bool found = false; if (m_skeleton) { - int resources = m_resourceManager->courseResources(m_language).count(); + int resources = m_repository->courseResources(m_language).count(); for (int i=0; i < resources; ++i) { - EditableCourseResource * course = m_resourceManager->course(m_language, i); + EditableCourseResource * course = m_repository->course(m_language, i); if (course->foreignId() == m_skeleton->id()) { setCourse(course); found = true; break; } } } if (!found) { setCourse(nullptr); } } else { // not skeleton mode - if (m_resourceManager->courseResources(m_language).count() > 0) { - setCourse(m_resourceManager->course(m_language, 0)); + if (m_repository->courseResources(m_language).count() > 0) { + setCourse(m_repository->course(m_language, 0)); } } emit languageChanged(); } EditableCourseResource * EditorSession::course() const { return m_course; } void EditorSession::setCourse(EditableCourseResource *course) { if (m_course == course) { return; } m_course = course; if (m_course && !m_course->unitList().isEmpty()) { setUnit(m_course->unitList().constFirst()); } else { setUnit(nullptr); } emit courseChanged(); } Unit * EditorSession::unit() const { return m_unit; } void EditorSession::setUnit(Unit *unit) { if (m_unit == unit) { return; } m_unit = unit; // different than above, do not directly enter phrases // but first show editing information for units setPhrase(nullptr); emit unitChanged(); } void EditorSession::setPhrase(Phrase *phrase) { if (m_phrase == phrase) { return; } if (phrase) { setUnit(phrase->unit()); } m_phrase = phrase; emit phraseChanged(); } Phrase * EditorSession::phrase() const { return m_phrase; } Phrase * EditorSession::previousPhrase() const { if (!m_phrase) { return nullptr; } const int index = m_phrase->unit()->phraseList().indexOf(m_phrase); if (index > 0) { return m_phrase->unit()->phraseList().at(index - 1); } else { Unit *unit = m_phrase->unit(); int uIndex = unit->course()->unitList().indexOf(unit); if (uIndex > 0) { return unit->course()->unitList().at(uIndex - 1)->phraseList().last(); } } return nullptr; } Phrase * EditorSession::nextPhrase() const { if (!m_phrase) { return nullptr; } const int index = m_phrase->unit()->phraseList().indexOf(m_phrase); if (index < m_phrase->unit()->phraseList().length() - 1) { return m_phrase->unit()->phraseList().at(index + 1); } else { Unit *unit = m_phrase->unit(); int uIndex = unit->course()->unitList().indexOf(unit); if (uIndex < unit->course()->unitList().length() - 1) { Unit *nextUnit = unit->course()->unitList().at(uIndex + 1); if (nextUnit->phraseList().isEmpty()) { return nullptr; } return nextUnit->phraseList().constFirst(); } } return nullptr; } void EditorSession::switchToPreviousPhrase() { setPhrase(previousPhrase()); } void EditorSession::switchToNextPhrase() { setPhrase(nextPhrase()); } bool EditorSession::hasPreviousPhrase() const { return previousPhrase() != nullptr; } bool EditorSession::hasNextPhrase() const { return nextPhrase() != nullptr; } void EditorSession::updateCourseFromSkeleton() { if (!m_course) { qCritical() << "Not updating course from skeleton, no one set."; return; } // m_resourceManager->updateCourseFromSkeleton(m_course); //FIXME } diff --git a/src/core/editorsession.h b/src/core/editorsession.h index bddc301..3ce9ffe 100644 --- a/src/core/editorsession.h +++ b/src/core/editorsession.h @@ -1,120 +1,120 @@ /* * 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" class QString; class Skeleton; class Language; class EditableCourseResource; class Unit; -class ResourceManager; +class ContributorRepository; /** * \class EditorSession * * An object of this class is used to set the current state of the editor. By this, we put all logic * how language, skeleton and course fit to each other into this class. The main concept is that * we have to fundamentally different workflows that both are modeled in this class: * * 1. Skeleton based workflow * - a skeleton is selected * - every language is available, since eventually the course should be available in every language * - for every language, there is at most one course (there is none only in case it is not created yet) * - adding new units or phrases is only possible in the skeleton course * - every course can update/sync with the skeleton * * 2. Course based workflow * - there is no skeleton from which the course is derived * - the base is a language that is selected first * - for a language there can be none to arbitrarily many courses * * The main switch is \c EditorSession::setSkeletonMode(bool) */ class ARTIKULATECORE_EXPORT EditorSession : public QObject { Q_OBJECT Q_PROPERTY(bool skeletonMode READ skeletonMode WRITE setSkeletonMode NOTIFY skeletonModeChanged) Q_PROPERTY(bool editSkeleton READ isEditSkeleton WRITE setEditSkeleton NOTIFY editSkeletonChanged) Q_PROPERTY(Skeleton *skeleton READ skeleton WRITE setSkeleton NOTIFY skeletonChanged) Q_PROPERTY(Language *language READ language WRITE setLanguage NOTIFY languageChanged) Q_PROPERTY(EditableCourseResource *course READ course WRITE setCourse NOTIFY courseChanged) //TODO interface should provde ICourse Q_PROPERTY(Unit *unit READ unit WRITE setUnit NOTIFY unitChanged) Q_PROPERTY(Phrase *phrase READ phrase WRITE setPhrase NOTIFY phraseChanged) Q_PROPERTY(bool hasNextPhrase READ hasNextPhrase NOTIFY phraseChanged) Q_PROPERTY(bool hasPreviousPhrase READ hasPreviousPhrase NOTIFY phraseChanged) public: explicit EditorSession(QObject *parent = nullptr); - void setResourceManager(ResourceManager *manager); + void setContributorRepository(ContributorRepository *manager); void setSkeletonMode(bool enabled=true); bool skeletonMode() const; void setEditSkeleton(bool enabled=true); bool isEditSkeleton() const; Skeleton * skeleton() const; void setSkeleton(Skeleton *skeleton); Language * language() const; void setLanguage(Language *language); EditableCourseResource * course() const; void setCourse(EditableCourseResource *course); Unit * unit() const; void setUnit(Unit *unit); Phrase * phrase() const; void setPhrase(Phrase *phrase); Phrase::Type phraseType() const; void setPhraseType(Phrase::Type type); bool hasPreviousPhrase() const; bool hasNextPhrase() const; Q_INVOKABLE void switchToPreviousPhrase(); Q_INVOKABLE void switchToNextPhrase(); Q_INVOKABLE void updateCourseFromSkeleton(); private: Phrase * nextPhrase() const; Phrase * previousPhrase() const; Q_SIGNALS: void editSkeletonChanged(); void skeletonModeChanged(); void skeletonChanged(); void languageChanged(); void courseChanged(); void unitChanged(); void phraseChanged(); private: Q_DISABLE_COPY(EditorSession) - ResourceManager * m_resourceManager; + ContributorRepository * m_repository; bool m_skeletonMode; bool m_editSkeleton; Skeleton *m_skeleton; Language *m_language; EditableCourseResource *m_course; EditableCourseResource *m_tmpCourseWhileSkeletonEditing; Unit *m_unit; Phrase *m_phrase; }; #endif diff --git a/src/core/resourcerepository.cpp b/src/core/resourcerepository.cpp index 4c3d799..7b892b5 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 "resources/languageresource.h" #include #include #include #include ResourceRepository::ResourceRepository(QObject *parent) : ResourceRepository(QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DataLocation).constFirst() + QStringLiteral("/courses/")), parent) { } ResourceRepository::ResourceRepository(const QUrl &storageLocation, QObject *parent) : IResourceRepository() , m_storageLocation(storageLocation.toLocalFile()) { // 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()); } } QString 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(Language *language) const { QVector courses; for (const auto &course : m_courses) { if (language != nullptr && course->language() != language) { 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->language()); } return languages; } Language * ResourceRepository::language(const QString &id) const { if (m_languages.contains(id)) { return m_languages.value(id)->language(); } 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); 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; } CourseResource *resource = new CourseResource(QUrl::fromLocalFile(resourceFile), this); if (resource->language() == nullptr) { resource->deleteLater(); 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) { - LanguageResource *resource = new LanguageResource(nullptr, QUrl::fromLocalFile(resourceFile)); //TODO hacky adapter code + LanguageResource *resource = new LanguageResource(QUrl::fromLocalFile(resourceFile)); if (!resource) { qCWarning(ARTIKULATE_CORE()) << "Could not load language" << resourceFile; resource->deleteLater(); return false; } if (m_languages.contains(resource->identifier())) { qCWarning(ARTIKULATE_CORE()) << "Could not load language" << resourceFile; resource->deleteLater(); return false; } m_languages.insert(resource->identifier(), resource); return true; } diff --git a/src/core/resources/languageresource.cpp b/src/core/resources/languageresource.cpp index c3eda69..d39c9e0 100644 --- a/src/core/resources/languageresource.cpp +++ b/src/core/resources/languageresource.cpp @@ -1,185 +1,180 @@ /* * 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 "languageresource.h" -#include "core/resourcemanager.h" +#include "courseparser.h" #include "core/language.h" #include "core/phoneme.h" #include "core/phonemegroup.h" #include #include #include #include #include #include "artikulate_debug.h" class LanguageResourcePrivate { public: - LanguageResourcePrivate(ResourceManager *resourceManager) - : m_resourceManager(resourceManager) - , m_languageResource(nullptr) - , m_type(ResourceInterface::LanguageResourceType) + LanguageResourcePrivate() + : m_languageResource(nullptr) { } ~LanguageResourcePrivate() { } - ResourceManager *m_resourceManager; Language *m_languageResource; QString m_identifier; QUrl m_path; QString m_title; QString m_i18nTitle; - ResourceInterface::Type m_type; }; -LanguageResource::LanguageResource(ResourceManager *resourceManager, const QUrl &path) - : ResourceInterface(resourceManager) - , d(new LanguageResourcePrivate(resourceManager)) +LanguageResource::LanguageResource(const QUrl &path) + : d(new LanguageResourcePrivate) { d->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") { d->m_identifier = xml.readElementText(); } if (xml.name() == "title") { d->m_title = xml.readElementText(); } if (xml.name() == "i18nTitle") { d->m_i18nTitle = xml.readElementText(); } // quit reading when basic elements are read if (!d->m_identifier.isEmpty() && !d->m_title.isEmpty() && !d->m_i18nTitle.isEmpty() ) { break; } } if (xml.hasError()) { qCritical() << "Error occurred when reading Language XML file:" << path.toLocalFile(); } } xml.clear(); file.close(); } LanguageResource::~LanguageResource() { } QString LanguageResource::identifier() { return d->m_identifier; } QString LanguageResource::title() { return d->m_title; } QString LanguageResource::i18nTitle() { return d->m_i18nTitle; } void LanguageResource::close() { // do nothing // language files are never closed } bool LanguageResource::isOpen() const { return (d->m_languageResource != nullptr); } QUrl LanguageResource::path() const { return d->m_path; } QObject * LanguageResource::resource() { if (d->m_languageResource != nullptr) { return d->m_languageResource; } if (!d->m_path.isLocalFile()) { qCWarning(ARTIKULATE_LOG) << "Cannot open language file at " << d->m_path.toLocalFile() << ", aborting."; return nullptr; } - QXmlSchema schema = loadXmlSchema(QStringLiteral("language")); + QXmlSchema schema = CourseParser::loadXmlSchema(QStringLiteral("language")); if (!schema.isValid()) { return nullptr; } - QDomDocument document = loadDomDocument(d->m_path, schema); + QDomDocument document = CourseParser::loadDomDocument(d->m_path, schema); if (document.isNull()) { qCWarning(ARTIKULATE_LOG) << "Could not parse document " << d->m_path.toLocalFile() << ", aborting."; return nullptr; } QDomElement root(document.documentElement()); d->m_languageResource = new Language(this); d->m_languageResource->setFile(d->m_path); d->m_languageResource->setId(root.firstChildElement(QStringLiteral("id")).text()); d->m_languageResource->setTitle(root.firstChildElement(QStringLiteral("title")).text()); d->m_languageResource->seti18nTitle(root.firstChildElement(QStringLiteral("i18nTitle")).text()); // create phoneme groups for (QDomElement groupNode = root.firstChildElement(QStringLiteral("phonemeGroups")).firstChildElement(); !groupNode.isNull(); groupNode = groupNode.nextSiblingElement()) { PhonemeGroup *group = d->m_languageResource->addPhonemeGroup( groupNode.firstChildElement(QStringLiteral("id")).text(), groupNode.firstChildElement(QStringLiteral("title")).text()); group->setDescription(groupNode.attribute(QStringLiteral("description"))); // register phonemes for (QDomElement phonemeNode = groupNode.firstChildElement(QStringLiteral("phonemes")).firstChildElement(); !phonemeNode.isNull(); phonemeNode = phonemeNode.nextSiblingElement()) { group->addPhoneme(phonemeNode.firstChildElement(QStringLiteral("id")).text(), phonemeNode.firstChildElement(QStringLiteral("title")).text()); } } return d->m_languageResource; } Language * LanguageResource::language() { return qobject_cast(resource()); } diff --git a/src/core/resources/languageresource.h b/src/core/resources/languageresource.h index 6544bd2..816ae12 100644 --- a/src/core/resources/languageresource.h +++ b/src/core/resources/languageresource.h @@ -1,88 +1,86 @@ /* * 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 LANGUAGERESOURCE_H #define LANGUAGERESOURCE_H #include "artikulatecore_export.h" -#include "resourceinterface.h" - #include class LanguageResourcePrivate; class Language; -class ARTIKULATECORE_EXPORT LanguageResource : public ResourceInterface +class ARTIKULATECORE_EXPORT LanguageResource : public QObject { Q_OBJECT public: - explicit LanguageResource(ResourceManager *resourceManager, const QUrl &path); + explicit LanguageResource(const QUrl &path); virtual ~LanguageResource(); /** * \return unique identifier */ - QString identifier() override; + QString identifier(); /** * \return human readable localized title */ - QString title() override; + QString title(); /** * \return human readable title in English */ - QString i18nTitle() override; + QString i18nTitle(); /** * \return true if resource is loaded, otherwise false */ - bool isOpen() const override; + bool isOpen() const; /** * close resource without writing changes back to file */ - void close() override; + void close(); /** * \return path to resource file */ - QUrl path() const override; + QUrl path() const; /** * \return reference to the loaded resource * if resource is not open yet, it will be loaded */ - QObject * resource() override; + QObject * resource(); /** * \return reference to the loaded language resource * Same behavior as \see resource() but casted to Language */ Language * language(); private: const QScopedPointer d; }; #endif diff --git a/src/core/resources/skeletonresource.cpp b/src/core/resources/skeletonresource.cpp index fdf905a..c4d7711 100644 --- a/src/core/resources/skeletonresource.cpp +++ b/src/core/resources/skeletonresource.cpp @@ -1,318 +1,313 @@ /* * 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 "core/resourcemanager.h" +#include "courseparser.h" #include "core/language.h" #include "core/skeleton.h" #include "core/unit.h" #include "core/phoneme.h" #include "core/phonemegroup.h" #include "core/resources/languageresource.h" #include #include #include #include #include #include "artikulate_debug.h" class SkeletonResourcePrivate { public: - SkeletonResourcePrivate(ResourceManager *resourceManager) - : m_resourceManager(resourceManager) - , m_skeletonResource(nullptr) - , m_type(ResourceInterface::SkeletonResourceType) + SkeletonResourcePrivate() + : m_skeletonResource(nullptr) { } ~SkeletonResourcePrivate() = default; - ResourceManager *m_resourceManager; QUrl m_path; QString m_identifier; QString m_title; QString m_i18nTitle; Skeleton *m_skeletonResource; - ResourceInterface::Type m_type; }; -SkeletonResource::SkeletonResource(ResourceManager *resourceManager, const QUrl &path) - : ResourceInterface(resourceManager) - , d(new SkeletonResourcePrivate(resourceManager)) +SkeletonResource::SkeletonResource(const QUrl &path) + : QObject() + , d(new SkeletonResourcePrivate) { d->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") { d->m_identifier = xml.readElementText(); continue; } if (xml.name() == "title") { d->m_title = xml.readElementText(); d->m_i18nTitle = d->m_title; continue; } //TODO i18nTitle must be implemented, currently missing and hence not parsed // quit reading when basic elements are read if (!d->m_identifier.isEmpty() && !d->m_title.isEmpty() && !d->m_i18nTitle.isEmpty() ) { break; } } if (xml.hasError()) { qCritical() << "Error occurred when reading Skeleton XML file:" << path.toLocalFile(); } } xml.clear(); file.close(); } -SkeletonResource::SkeletonResource(ResourceManager* resourceManager, Skeleton *skeleton) - : ResourceInterface(resourceManager) - , d(new SkeletonResourcePrivate(resourceManager)) +SkeletonResource::SkeletonResource(Skeleton *skeleton) + : QObject() + , d(new SkeletonResourcePrivate) { - d->m_type = ResourceInterface::SkeletonResourceType; d->m_path = skeleton->file(); d->m_identifier = skeleton->id(); d->m_title = skeleton->title(); d->m_skeletonResource = skeleton; } SkeletonResource::~SkeletonResource() { } QString SkeletonResource::identifier() { if (d->m_skeletonResource) { return d->m_skeletonResource->id(); } return d->m_identifier; } QString SkeletonResource::title() { if (d->m_skeletonResource) { return d->m_skeletonResource->title(); } return d->m_title; } QString SkeletonResource::i18nTitle() { if (d->m_skeletonResource) { return d->m_skeletonResource->title(); //TODO } return d->m_i18nTitle; } void SkeletonResource::close() { d->m_skeletonResource->deleteLater(); d->m_skeletonResource = nullptr; } void SkeletonResource::sync() { Q_ASSERT(path().isValid()); Q_ASSERT(path().isLocalFile()); Q_ASSERT(!path().isEmpty()); // if resource was never loaded, it cannot be changed if (!d->m_skeletonResource) { qCDebug(ARTIKULATE_LOG) << "Aborting sync, skeleton was not parsed."; return; } // // not writing back if not modified // if (!d->m_skeletonResource->modified()) { // qCDebug(ARTIKULATE_LOG) << "Aborting sync, skeleton was not modified."; // return; // } 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(d->m_skeletonResource->id())); titleElement.appendChild(document.createTextNode(d->m_skeletonResource->title())); descriptionElement.appendChild(document.createTextNode(d->m_skeletonResource->description())); QDomElement unitListElement = document.createElement(QStringLiteral("units")); // create units foreach (Unit *unit, d->m_skeletonResource->unitList()) { 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 foreach (Phrase *phrase, unit->phraseList()) { 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); // write back to file //TODO port to KSaveFile QFile file(path().toLocalFile()); if (!file.open(QIODevice::WriteOnly)) { qCWarning(ARTIKULATE_LOG) << "Unable to open file " << file.fileName() << " in write mode, aborting."; return; } file.write(document.toByteArray()); return; } void SkeletonResource::reload() { qCritical() << "NOT IMPLEMENTED"; } bool SkeletonResource::isOpen() const { return (d->m_skeletonResource != nullptr); } QUrl SkeletonResource::path() const { if (d->m_skeletonResource) { return d->m_skeletonResource->file(); } return d->m_path; } QObject * SkeletonResource::resource() { if (d->m_skeletonResource) { return d->m_skeletonResource; } if (!path().isLocalFile()) { qCWarning(ARTIKULATE_LOG) << "Cannot open skeleton file at " << path().toLocalFile() << ", aborting."; return nullptr; } - QXmlSchema schema = loadXmlSchema(QStringLiteral("skeleton")); + QXmlSchema schema = CourseParser::loadXmlSchema(QStringLiteral("skeleton")); if (!schema.isValid()) { return nullptr; } - QDomDocument document = loadDomDocument(path(), schema); + QDomDocument document = CourseParser::loadDomDocument(path(), schema); if (document.isNull()) { qCWarning(ARTIKULATE_LOG) << "Could not parse document " << path().toLocalFile() << ", aborting."; return nullptr; } // create skeleton QDomElement root(document.documentElement()); - d->m_skeletonResource = new Skeleton(this); + d->m_skeletonResource = new Skeleton(); d->m_skeletonResource->setFile(d->m_path); d->m_skeletonResource->setId(root.firstChildElement(QStringLiteral("id")).text()); d->m_skeletonResource->setTitle(root.firstChildElement(QStringLiteral("title")).text()); d->m_skeletonResource->setDescription(root.firstChildElement(QStringLiteral("title")).text()); // create units for (QDomElement unitNode = root.firstChildElement(QStringLiteral("units")).firstChildElement(); !unitNode.isNull(); unitNode = unitNode.nextSiblingElement()) { Unit *unit = new Unit(d->m_skeletonResource); unit->setId(unitNode.firstChildElement(QStringLiteral("id")).text()); unit->setCourse(d->m_skeletonResource); unit->setTitle(unitNode.firstChildElement(QStringLiteral("title")).text()); d->m_skeletonResource->addUnit(unit); // create phrases for (QDomElement phraseNode = unitNode.firstChildElement(QStringLiteral("phrases")).firstChildElement(); !phraseNode.isNull(); phraseNode = phraseNode.nextSiblingElement()) { Phrase *phrase = new Phrase(unit); phrase->setId(phraseNode.firstChildElement(QStringLiteral("id")).text()); phrase->setText(phraseNode.firstChildElement(QStringLiteral("text")).text()); phrase->setType(phraseNode.firstChildElement(QStringLiteral("type")).text()); phrase->setUnit(unit); unit->addPhrase(phrase); } } d->m_skeletonResource->setModified(false); return d->m_skeletonResource; } Skeleton * SkeletonResource::skeleton() { return qobject_cast(resource()); } diff --git a/src/core/resources/skeletonresource.h b/src/core/resources/skeletonresource.h index 52b7493..e35c98e 100644 --- a/src/core/resources/skeletonresource.h +++ b/src/core/resources/skeletonresource.h @@ -1,100 +1,99 @@ /* * 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 SKELETONRESOURCE_H #define SKELETONRESOURCE_H #include "artikulatecore_export.h" -#include "resourceinterface.h" #include class SkeletonResourcePrivate; class Skeleton; -class ARTIKULATECORE_EXPORT SkeletonResource : public ResourceInterface +class ARTIKULATECORE_EXPORT SkeletonResource : public QObject { Q_OBJECT void course(QString text); public: /** * Create course resource from file. */ - explicit SkeletonResource(ResourceManager *resourceManager, const QUrl &path); + explicit SkeletonResource(const QUrl &path); /** * Create course resource from course. */ - explicit SkeletonResource(ResourceManager *resourceManager, Skeleton *skeleton); + explicit SkeletonResource(Skeleton *skeleton); virtual ~SkeletonResource(); /** * \return unique identifier */ - QString identifier() override; + QString identifier(); /** * \return human readable localized title */ - QString title() override; + QString title(); /** * \return human readable title in English */ - QString i18nTitle() override; + QString i18nTitle(); /** * \return true if resource is loaded, otherwise false */ - bool isOpen() const override; + bool isOpen() const; /** * close resource without writing changes back to file */ - void close() override; + void close(); - void sync() override; + void sync(); - void reload() override; + void reload(); /** * \return path to resource file */ - QUrl path() const override; + QUrl path() const; /** * \return reference to the loaded resource * if resource is not open yet, it will be loaded */ - QObject * resource() override; + QObject * resource(); /** * \return reference to the loaded skeleton resource * Same behavior as \see resource() but casted to Skeleton */ Skeleton * skeleton(); private: const QScopedPointer d; }; #endif diff --git a/src/core/skeleton.cpp b/src/core/skeleton.cpp index e01f92e..a4585ce 100644 --- a/src/core/skeleton.cpp +++ b/src/core/skeleton.cpp @@ -1,49 +1,48 @@ /* * 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 "skeleton.h" #include "resources/skeletonresource.h" #include "resources/editablecourseresource.h" #include "unit.h" #include "language.h" -#include "resourcemanager.h" #include "phonemegroup.h" #include "artikulate_debug.h" #include #include #include #include -Skeleton::Skeleton(ResourceInterface *resource) +Skeleton::Skeleton(SkeletonResource *resource) : EditableCourseResource(QUrl(), nullptr) //FIXME thus just compiles but not more - , m_resource(qobject_cast(resource)) + , m_resource(resource) { } void Skeleton::sync() { if (!file().isValid() || file().isEmpty() || m_resource == nullptr) { qCWarning(ARTIKULATE_LOG()) << "No file path set, aborting sync operation."; return; } m_resource->sync(); setModified(false); } diff --git a/src/core/skeleton.h b/src/core/skeleton.h index 62190f8..6d9e41c 100644 --- a/src/core/skeleton.h +++ b/src/core/skeleton.h @@ -1,52 +1,52 @@ /* * 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 SKELETON_H #define SKELETON_H #include "artikulatecore_export.h" #include "resources/editablecourseresource.h" #include #include #include class ResourceInterface; class SkeletonResource; class ARTIKULATECORE_EXPORT Skeleton : public EditableCourseResource { Q_OBJECT public: - explicit Skeleton(ResourceInterface *resource = nullptr); + explicit Skeleton(SkeletonResource *resource = nullptr); /** * Writes course object back to file and set \ref modified state to false. * If no file is set, no operation is performed. */ Q_INVOKABLE void sync(); private: Q_DISABLE_COPY(Skeleton) SkeletonResource * const m_resource; }; #endif // SKELETON_H diff --git a/src/main.cpp b/src/main.cpp index 5e2c084..4745859 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,68 +1,68 @@ /* * 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 "version.h" #include #include #include #include "artikulate_debug.h" int main(int argc, char **argv) { - KLocalizedString::setApplicationDomain("artikulate"); Application app(argc, argv); + KLocalizedString::setApplicationDomain("artikulate"); ResourceRepository repository; repository.reloadCourses(); app.installResourceRepository(&repository); 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-2017 The Artikulate Developers"), i18nc("@title Short program description", "Training your pronunciation in a foreign language.") ); 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", "Oindrila Gupta"), i18nc("@info:credit Role", "Developer and Course Data")); aboutData.addAuthor(i18nc("@info:credit Developer name", "Magdalena Konkiewicz"), i18nc("@info:credit Role", "Developer and Course Data")); 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 2a35896..112520e 100644 --- a/src/main_editor.cpp +++ b/src/main_editor.cpp @@ -1,57 +1,61 @@ /* * 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 #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-2016 The Artikulate Developers").toString(), + ki18nc("@info:credit", "(c) 2013-2019 The Artikulate Developers").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")); KAboutData::setApplicationData(aboutData); KCrash::initialize(); - MainWindowEditor *mainWindow = new MainWindowEditor(); + MainWindowEditor *mainWindow = new MainWindowEditor(&repository); QSize size(800, 600); mainWindow->setMinimumSize(size); mainWindow->show(); return app.exec(); } diff --git a/src/mainwindow_editor.cpp b/src/mainwindow_editor.cpp index 64ef868..57e8916 100644 --- a/src/mainwindow_editor.cpp +++ b/src/mainwindow_editor.cpp @@ -1,198 +1,198 @@ /* * 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/resourcesdialogpage.h" #include "ui/sounddevicedialogpage.h" #include "ui/appearencedialogpage.h" #include "ui/exportghnsdialog.h" -#include "core/resourcemanager.h" #include "core/editorsession.h" #include "core/resources/courseresource.h" #include "models/languagemodel.h" #include "settings.h" #include "libsound/src/outputdevicecontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include "artikulate_debug.h" #include #include #include #include #include #include #include #include #include #include using namespace LearnerProfile; -MainWindowEditor::MainWindowEditor() - : m_resourceManager(new ResourceManager(this)) - , m_editorSession(new EditorSession(this)) +MainWindowEditor::MainWindowEditor(ContributorRepository *repository) + : m_repository(repository) + , m_editorSession(new EditorSession()) , m_widget(new QQuickWidget) { - m_editorSession->setResourceManager(m_resourceManager); + m_editorSession->setContributorRepository(m_repository); setWindowIcon(QIcon::fromTheme(QStringLiteral("artikulate"))); setWindowTitle(qAppName()); setAutoSaveSettings(); // workaround for QTBUG-40765 qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); // load saved sound settings OutputDeviceController::self().setVolume(Settings::audioOutputVolume()); // load resources - m_resourceManager->loadLanguageResources(); - if (m_resourceManager->languageResources().count() == 0) { + m_repository->loadLanguageResources(); + if (m_repository->languageResources().count() == 0) { qFatal("No language resources found, cannot start application."); } - m_resourceManager->loadCourseResources(); + m_repository->loadCourseResources(); // create menu setupActions(); // set view m_widget->resize(QSize(800, 600)); m_widget->rootContext()->setContextObject(new KLocalizedContext(m_widget)); - m_widget->rootContext()->setContextProperty(QStringLiteral("g_resourceManager"), m_resourceManager); - m_widget->rootContext()->setContextProperty(QStringLiteral("editorSession"), m_editorSession); + m_widget->rootContext()->setContextProperty(QStringLiteral("g_resourceManager"), m_repository); + m_widget->rootContext()->setContextProperty(QStringLiteral("editorSession"), m_repository); // set starting screen m_widget->setSource(QUrl(QStringLiteral("qrc:/artikulate/qml/Editor.qml"))); m_widget->setResizeMode(QQuickWidget::SizeRootObjectToView); QAction *newAct = KStandardAction::save(this, SLOT(save()), actionCollection()); actionCollection()->addAction(QStringLiteral("save"), newAct); // set status bar statusBar()->setEnabled(true); QLabel *repositoryLabel = new QLabel; - repositoryLabel->setText(i18n("Course Repository: %1", m_resourceManager->repositoryUrl())); - connect(m_resourceManager, &ResourceManager::repositoryChanged, this, [=]() { - repositoryLabel->setText(i18n("Course Repository: %1", m_resourceManager->repositoryUrl())); + repositoryLabel->setText(i18n("Course Repository: %1", m_repository->storageLocation())); + connect(m_repository, &ContributorRepository::repositoryChanged, this, [=]() { + repositoryLabel->setText(i18n("Course Repository: %1", m_repository->storageLocation())); }); statusBar()->insertWidget(0, repositoryLabel); createGUI(QStringLiteral("artikulateui_editor.rc")); setCentralWidget(m_widget); } MainWindowEditor::~MainWindowEditor() { // save current settings for case of closing Settings::self()->save(); } -ResourceManager * MainWindowEditor::resourceManager() const +ContributorRepository * MainWindowEditor::resourceRepository() const { - return m_resourceManager; + 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_resourceManager); + 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()); setupGUI(Keys | Save | Create, QStringLiteral("artikulateui_editor.rc")); } void MainWindowEditor::showSettingsDialog() { if (KConfigDialog::showDialog(QStringLiteral("settings"))) { return; } QPointer dialog = new KConfigDialog(nullptr, QStringLiteral("settings"), Settings::self()); - ResourcesDialogPage *resourceDialog = new ResourcesDialogPage(m_resourceManager); + ResourcesDialogPage *resourceDialog = new ResourcesDialogPage(m_repository); SoundDeviceDialogPage *soundDialog = new SoundDeviceDialogPage(); AppearenceDialogPage *appearenceDialog = new AppearenceDialogPage(); resourceDialog->loadSettings(); soundDialog->loadSettings(); appearenceDialog->loadSettings(); dialog->addPage(soundDialog, i18nc("@item:inmenu", "Sound Devices"), QStringLiteral("audio-headset"), i18nc("@title:tab", "Sound Device Settings"), true); dialog->addPage(appearenceDialog, i18nc("@item:inmenu", "Fonts"), QStringLiteral("preferences-desktop-font"), i18nc("@title:tab", "Training Phrase Font"), true); dialog->addPage(resourceDialog, i18nc("@item:inmenu", "Course Resources"), QStringLiteral("repository"), i18nc("@title:tab", "Resource Repository Settings"), true); connect(dialog.data(), &QDialog::accepted, resourceDialog, &ResourcesDialogPage::saveSettings); connect(dialog.data(), &QDialog::accepted, soundDialog, &SoundDeviceDialogPage::saveSettings); connect(dialog.data(), &QDialog::accepted, appearenceDialog, &AppearenceDialogPage::saveSettings); dialog->exec(); } void MainWindowEditor::save() { - m_resourceManager->sync(); + m_repository->sync(); } void MainWindowEditor::quit() { if (queryClose()) { qApp->quit(); } } bool MainWindowEditor::queryClose() { - if (!m_resourceManager->modified()) { + 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_resourceManager->sync(); + 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 e4f1890..1a68186 100644 --- a/src/mainwindow_editor.h +++ b/src/mainwindow_editor.h @@ -1,73 +1,72 @@ /* * 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 -#include "core/resourcemanager.h" +#include "core/contributorrepository.h" #include "core/trainingsession.h" class EditorSession; class KActionCollection; class KMenu; class QQuickWidget; class MainWindowEditor : public KXmlGuiWindow { Q_OBJECT - Q_PROPERTY(ResourceManager *globalResourceManager READ resourceManager CONSTANT) public: /** * Default Constructor */ - MainWindowEditor(); + MainWindowEditor(ContributorRepository *repository); /** * Default Destructor */ virtual ~MainWindowEditor(); - ResourceManager * resourceManager() const; + ContributorRepository * resourceRepository() const; void setupActions(); QSize sizeHint() const override { return QSize(1000, 700); } bool queryClose() override; public Q_SLOTS: void showSettingsDialog(); void save(); void quit(); Q_SIGNALS: void modeChanged(bool); private: - ResourceManager *m_resourceManager; + ContributorRepository *m_repository; EditorSession *m_editorSession; QQuickWidget *m_widget; }; #endif diff --git a/src/models/languageresourcemodel.cpp b/src/models/languageresourcemodel.cpp index 0a31bef..4a260cc 100644 --- a/src/models/languageresourcemodel.cpp +++ b/src/models/languageresourcemodel.cpp @@ -1,232 +1,217 @@ /* * 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 "core/language.h" -#include "core/resourcemanager.h" +#include "core/iresourcerepository.h" #include "core/resources/languageresource.h" #include "core/resources/courseresource.h" #include #include #include #include "artikulate_debug.h" LanguageResourceModel::LanguageResourceModel(QObject* parent) : QAbstractListModel(parent) - , m_resourceManager(nullptr) + , m_repository(nullptr) , m_view(LanguageModel::NonEmptyGhnsOnlyLanguages) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitLanguageChanged(int))); } QHash< int, QByteArray > LanguageResourceModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[I18nTitleRole] = "i18nTitle"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; roles[CourseNumberRole] = "courseNumberRole"; return roles; } -void LanguageResourceModel::setResourceManager(ResourceManager *resourceManager) +void LanguageResourceModel::setResourceRepository(IResourceRepository *repository) { - if (m_resourceManager == resourceManager) { + if (m_repository == repository) { return; } beginResetModel(); - - if (m_resourceManager) { - m_resourceManager->disconnect(this); - } - - m_resourceManager = resourceManager; - - if (m_resourceManager) { - connect(m_resourceManager, &ResourceManager::languageResourceAboutToBeAdded, - this, &LanguageResourceModel::onLanguageResourceAboutToBeAdded); - connect(m_resourceManager, &ResourceManager::languageResourceAdded, - this, &LanguageResourceModel::onLanguageResourceAdded); - connect(m_resourceManager, &ResourceManager::languageResourceAboutToBeRemoved, - this, &LanguageResourceModel::onLanguageResourceAboutToBeRemoved); - connect(m_resourceManager, &ResourceManager::languageResourceRemoved, - this, &LanguageResourceModel::onLanguageResourceRemoved); - connect(m_resourceManager, &ResourceManager::languageCoursesChanged, - this, &LanguageResourceModel::updateDisplayedLanguages); + if (m_repository) { + m_repository->disconnect(this); } + m_repository = repository; updateResources(); - endResetModel(); - emit resourceManagerChanged(); + emit resourceRepositoryChanged(); } -ResourceManager * LanguageResourceModel::resourceManager() const +IResourceRepository * LanguageResourceModel::resourceRepository() const { - return m_resourceManager; + return m_repository; } QVariant LanguageResourceModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() >= m_resources.count()) { return QVariant(); } Language * const language = m_resources.at(index.row())->language(); 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_resources.count(); default: return QVariant(); } } int LanguageResourceModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_resources.count(); } void LanguageResourceModel::onLanguageResourceAboutToBeAdded(LanguageResource *resource, int index) { beginInsertRows(QModelIndex(), index, index); m_resources.append(resource); connect(resource->language(), SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); connect(resource->language(), SIGNAL(phonemesChanged()), m_signalMapper, SLOT(map())); connect(resource->language(), SIGNAL(phonemeGroupsChanged()), m_signalMapper, SLOT(map())); } void LanguageResourceModel::onLanguageResourceAdded() { updateMappings(); endInsertRows(); } void LanguageResourceModel::onLanguageResourceAboutToBeRemoved(int index) { - if (!m_resourceManager) { - return; - } + //FIXME adapt to repository +// if (!m_repository) { +// return; +// } - LanguageResource *originalResource = m_resourceManager->languageResources().at(index); - int modelIndex = m_resources.indexOf(originalResource); +// LanguageResource *originalResource = m_repository->languages().at(index); +// int modelIndex = m_resources.indexOf(originalResource); - if (modelIndex == -1) { - qCWarning(ARTIKULATE_LOG) << "Cannot remove language from model, not registered"; - return; - } - beginRemoveRows(QModelIndex(), modelIndex, modelIndex); - originalResource->disconnect(m_signalMapper); - m_resources.removeAt(modelIndex); +// if (modelIndex == -1) { +// qCWarning(ARTIKULATE_LOG) << "Cannot remove language from model, not registered"; +// return; +// } +// beginRemoveRows(QModelIndex(), modelIndex, modelIndex); +// originalResource->disconnect(m_signalMapper); +// m_resources.removeAt(modelIndex); } void LanguageResourceModel::onLanguageResourceRemoved() { 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; } beginResetModel(); m_view = view; updateResources(); endResetModel(); } void LanguageResourceModel::updateDisplayedLanguages() { beginResetModel(); updateResources(); endResetModel(); } LanguageModel::LanguageResourceView LanguageResourceModel::view() const { return m_view; } void LanguageResourceModel::updateResources() { - if (!m_resourceManager) { + if (!m_repository) { return; } m_resources.clear(); - QList resources = m_resourceManager->languageResources(); - - for (LanguageResource *language : resources) { - m_resources.append(language); - } + QVector resources = m_repository->languages(); +//FIXME complete switch to language resources +// for (LanguageResource *language : resources) { +// m_resources.append(language); +// } updateMappings(); } void LanguageResourceModel::updateMappings() { int languages = m_resources.count(); for (int i = 0; i < languages; i++) { m_signalMapper->setMapping(m_resources.at(i), i); } } diff --git a/src/models/languageresourcemodel.h b/src/models/languageresourcemodel.h index 636abf7..ec247ff 100644 --- a/src/models/languageresourcemodel.h +++ b/src/models/languageresourcemodel.h @@ -1,80 +1,80 @@ /* * 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" -class ResourceManager; +class IResourceRepository; class LanguageResource; class Language; class QSignalMapper; class LanguageResourceModel : public QAbstractListModel { Q_OBJECT - Q_PROPERTY(ResourceManager *resourceManager READ resourceManager WRITE setResourceManager NOTIFY resourceManagerChanged) + Q_PROPERTY(IResourceRepository *resourceRepository READ resourceRepository WRITE setResourceRepository NOTIFY resourceRepositoryChanged) public: enum LanguageRoles { TitleRole = Qt::UserRole + 1, I18nTitleRole, IdRole, DataRole, CourseNumberRole }; explicit LanguageResourceModel(QObject *parent = nullptr); /** * Reimplemented from QAbstractListModel::roleNames() */ virtual QHash roleNames() const override; - void setResourceManager(ResourceManager *resourceManager); - ResourceManager * resourceManager() const; + void setResourceRepository(IResourceRepository *repository); + 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 resourceManagerChanged(); + void resourceRepositoryChanged(); private Q_SLOTS: void onLanguageResourceAboutToBeAdded(LanguageResource *resource, int index); void onLanguageResourceAdded(); void onLanguageResourceAboutToBeRemoved(int index); void onLanguageResourceRemoved(); void emitLanguageChanged(int row); void updateDisplayedLanguages(); private: void updateResources(); void updateMappings(); - ResourceManager *m_resourceManager; + IResourceRepository *m_repository; QList m_resources; LanguageModel::LanguageResourceView m_view; QSignalMapper *m_signalMapper; }; #endif diff --git a/src/models/skeletonmodel.cpp b/src/models/skeletonmodel.cpp index c3fa743..d651ba8 100644 --- a/src/models/skeletonmodel.cpp +++ b/src/models/skeletonmodel.cpp @@ -1,186 +1,186 @@ /* * 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 "core/icourse.h" -#include "core/resourcemanager.h" +#include "core/contributorrepository.h" #include "core/skeleton.h" #include "core/resources/skeletonresource.h" #include #include #include #include "artikulate_debug.h" SkeletonModel::SkeletonModel(QObject *parent) : QAbstractListModel(parent) - , m_resourceManager(nullptr) + , m_repository(nullptr) , m_signalMapper(new QSignalMapper(this)) { connect(m_signalMapper, SIGNAL(mapped(int)), SLOT(emitSkeletonChanged(int))); } QHash< int, QByteArray > SkeletonModel::roleNames() const { QHash roles; roles[TitleRole] = "title"; roles[DescriptionRole] = "description"; roles[IdRole] = "id"; roles[DataRole] = "dataRole"; return roles; } -void SkeletonModel::setResourceManager(ResourceManager *resourceManager) +void SkeletonModel::setResourceRepository(ContributorRepository *repository) { - if (m_resourceManager == resourceManager) { + if (m_repository == repository) { return; } beginResetModel(); - if (m_resourceManager) { - m_resourceManager->disconnect(this); + if (m_repository) { + m_repository->disconnect(this); } - m_resourceManager = resourceManager; + m_repository = repository; - if (m_resourceManager) { + if (m_repository) { //FIXME // connect(m_resourceManager, &ResourceManager::skeletonAboutToBeAdded, this, &SkeletonModel::onSkeletonAboutToBeAdded); // connect(m_resourceManager, &ResourceManager::skeletonAdded, this, &SkeletonModel::onSkeletonAdded); // connect(m_resourceManager, &ResourceManager::skeletonAboutToBeRemoved, this, &SkeletonModel::onSkeletonsAboutToBeRemoved); // connect(m_resourceManager, &ResourceManager::skeletonRemoved, this, &SkeletonModel::onSkeletonsRemoved); } endResetModel(); - emit resourceManagerChanged(); + emit resourceRepositoryChanged(); } -ResourceManager * SkeletonModel::resourceManager() const +ContributorRepository * SkeletonModel::resourceRepository() const { - return m_resourceManager; + return m_repository; } QVariant SkeletonModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } - if (index.row() >= m_resourceManager->skeletonResources().count()) { + if (index.row() >= m_repository->skeletonResources().count()) { return QVariant(); } - Skeleton * const skeleton = m_resourceManager->skeletonResources().at(index.row())->skeleton(); + Skeleton * const skeleton = m_repository->skeletonResources().at(index.row())->skeleton(); 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); default: return QVariant(); } } int SkeletonModel::rowCount(const QModelIndex &parent) const { - if (!m_resourceManager) { + if (!m_repository) { return 0; } if (parent.isValid()) { return 0; } - return m_resourceManager->skeletonResources().count(); + return m_repository->skeletonResources().count(); } void SkeletonModel::onSkeletonAboutToBeAdded(ICourse *skeleton, int index) { connect(skeleton, SIGNAL(titleChanged()), m_signalMapper, SLOT(map())); //TODO add missing signals beginInsertRows(QModelIndex(), index, index); } void SkeletonModel::onSkeletonAdded() { updateMappings(); endInsertRows(); emit countChanged(); } void SkeletonModel::onSkeletonsAboutToBeRemoved(int first, int last) { beginRemoveRows(QModelIndex(), first, last); } void SkeletonModel::onSkeletonsRemoved() { endRemoveRows(); emit countChanged(); } void SkeletonModel::emitSkeletonChanged(int row) { emit skeletonChanged(row); emit dataChanged(index(row, 0), index(row, 0)); } 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")); } int SkeletonModel::count() const { - return m_resourceManager->skeletonResources().count(); + return m_repository->skeletonResources().count(); } void SkeletonModel::updateMappings() { - int skeletons = m_resourceManager->skeletonResources().count(); + int skeletons = m_repository->skeletonResources().count(); for (int i = 0; i < skeletons; ++i) { - m_signalMapper->setMapping(m_resourceManager->skeletonResources().at(i)->skeleton(), i); + m_signalMapper->setMapping(m_repository->skeletonResources().at(i)->skeleton(), i); } } 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 b1338f2..cffc39d 100644 --- a/src/models/skeletonmodel.h +++ b/src/models/skeletonmodel.h @@ -1,77 +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 SKELETONMODEL_H #define SKELETONMODEL_H #include -class ResourceManager; +class ContributorRepository; class ICourse; class Skeleton; class Language; class QSignalMapper; class SkeletonModel : public QAbstractListModel { Q_OBJECT - Q_PROPERTY(ResourceManager *resourceManager READ resourceManager WRITE setResourceManager NOTIFY resourceManagerChanged) + Q_PROPERTY(ContributorRepository *resourceRepository READ resourceRepository WRITE setResourceRepository NOTIFY resourceRepositoryChanged) Q_PROPERTY(int count READ count NOTIFY countChanged) public: enum courseRoles { TitleRole = Qt::UserRole + 1, DescriptionRole, IdRole, DataRole }; explicit SkeletonModel(QObject *parent = nullptr); - void setResourceManager(ResourceManager *resourceManager); + void setResourceRepository(ContributorRepository *repository); /** * Reimplemented from QAbstractListModel::roleNames() */ virtual QHash roleNames() const override; - ResourceManager * resourceManager() const; + ContributorRepository * 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; int count() const; Q_INVOKABLE QVariant skeleton(int index) const; Q_SIGNALS: void skeletonChanged(int index); - void resourceManagerChanged(); + void resourceRepositoryChanged(); void countChanged(); private Q_SLOTS: void onSkeletonAboutToBeAdded(ICourse *skeleton, int index); void onSkeletonAdded(); void onSkeletonsAboutToBeRemoved(int first, int last); void onSkeletonsRemoved(); void emitSkeletonChanged(int row); private: void updateMappings(); - ResourceManager *m_resourceManager; + ContributorRepository *m_repository; QSignalMapper *m_signalMapper; }; #endif // SKELETONMODEL_H diff --git a/src/qml/Editor.qml b/src/qml/Editor.qml index a03e198..383b49a 100644 --- a/src/qml/Editor.qml +++ b/src/qml/Editor.qml @@ -1,269 +1,268 @@ /* * 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 . */ import QtQuick 2.5 import QtQuick.Controls 2.3 import QtQuick.Controls 1.4 as QQC1 import QtQuick.Layouts 1.2 import QtQml.Models 2.2 import artikulate 1.0 Item { id: root width: 400 //parent.width height: 400 //parent.height Item { id: theme property string backgroundColor: "#ffffff" property int smallIconSize: 18 property int smallMediumIconSize: 22 property int mediumIconSize: 32 property int fontPointSize: 11 } LanguageModel { id: languageModel view: LanguageModel.AllLanguages resourceModel: LanguageResourceModel { resourceManager: g_resourceManager } } CourseModel { id: courseModel - resourceManager: g_resourceManager language: editorSession.language } UnitModel { id: selectedUnitModel course: editorSession.course } ColumnLayout { id: main anchors { fill: parent topMargin: 20 rightMargin: 20 bottomMargin: 20 leftMargin: 20 } spacing: 10 RowLayout { Label { visible: !g_resourceManager.isRepositoryManager text: i18n("no repository set") color: "red" } Label { text: i18n("Course Prototype:") } ComboBox { Layout.minimumWidth: 300 model: SkeletonModel { id: skeletonModel resourceManager: g_resourceManager } textRole: "title" onCurrentIndexChanged: { editorSession.skeleton = skeletonModel.skeleton(currentIndex) } } Button { id: buttonEditSkeleton Layout.minimumWidth: 200 text: i18n("Edit Prototype") icon.name: "code-class" checkable: true onClicked: editorSession.editSkeleton = checked } Item { Layout.fillWidth: true } Button { id: buttonSyncFromSkeleton enabled: !buttonEditSkeleton.checked Layout.minimumWidth: 200 text: i18n("Sync Prototype") icon.name: "view-refresh" ToolTip.visible: hovered ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.text: i18n("Update the course with elements from prototype.") onClicked: editorSession.updateCourseFromSkeleton() } CheckBox { Layout.alignment: Qt.AlignRight enabled: false//FIXME for now deactivating non-skeleton mode text: i18n("Prototype Mode") checked: editorSession.skeletonMode onClicked: { editorSession.skeletonMode = !editorSession.skeletonMode } } } RowLayout { id: languageRow Label { text: i18n("Language:") } ComboBox { Layout.minimumWidth: 200 Layout.fillWidth: true enabled: !buttonEditSkeleton.checked model: languageModel textRole: "i18nTitle" onCurrentIndexChanged: { editorSession.language = languageModel.language(currentIndex) } } } RowLayout { id: courseRow visible: { if (buttonEditSkeleton.checked) { return false } if (editorSession.skeletonMode && editorSession.course !== null) { return false } if (!editorSession.skeletonMode && editorSession.language !== null && editorSession.course !== null ) { return false } return true } Label { text: i18n("There is no course in the selected language.") } ComboBox { // course selection only necessary when we do not edit skeleton derived course id: comboCourse visible: !editorSession.skeletonMode Layout.fillWidth: true model: courseModel textRole: "title" onCurrentIndexChanged: { if (courseModel.course(currentIndex)) { editorSession.course = courseModel.course(currentIndex) } } onVisibleChanged: { if (visible && courseModel.course(currentIndex)) { editorSession.course = courseModel.course(currentIndex) } } } Button { text: i18n("Create Course") icon.name: "journal-new" onClicked: { editorSession.course = g_resourceManager.createCourse(editorSession.language, editorSession.skeleton) } } Item { Layout.fillHeight: true } //dummy } RowLayout { id: mainRow visible: editorSession.course !== null Layout.fillHeight: true ColumnLayout { ScrollView { Layout.minimumWidth: Math.floor(main.width * 0.3) Layout.fillHeight: true QQC1.TreeView { id: phraseTree height: { mainRow.height - (newUnitButton.visible ? newUnitButton.height : 0) - 10 } width: Math.floor(main.width * 0.3) - 20 QQC1.TableViewColumn { title: i18n("Units & Phrases") role: "text" } model: PhraseModel { id: phraseModel course: editorSession.course } selection: ItemSelectionModel { model: phraseTree.model } itemDelegate: Item { Text { anchors.verticalCenter: parent.verticalCenter color: styleData.textColor elide: styleData.elideMode text: styleData.value } } onClicked: { if (phraseModel.isPhrase(index)) { editorSession.phrase = phraseModel.phrase(index) } else { editorSession.phrase = null editorSession.unit = phraseModel.unit(index) } } Connections { target: editorSession onPhraseChanged: { if (editorSession.phrase === null) { return } phraseTree.expand(phraseModel.indexUnit(editorSession.phrase.unit)) phraseTree.selection.setCurrentIndex( phraseModel.indexPhrase(editorSession.phrase), ItemSelectionModel.ClearAndSelect) } } } } Button { // add units only if skeleton id: newUnitButton visible: !editorSession.skeletonMode || editorSession.editSkeleton icon.name: "list-add" text: i18n("New Unit") onClicked: phraseModel.course.createUnit() } } ColumnLayout { UnitEditor { visible: editorSession.unit !== null && editorSession.phrase === null unit: editorSession.unit editPhrases: editorSession.skeletonMode && editorSession.editSkeleton } PhraseEditor { visible: editorSession.phrase !== null phrase: editorSession.phrase isSkeletonPhrase: editorSession.editSkeleton Layout.minimumWidth: Math.floor(main.width * 0.6) Layout.fillHeight: true } } } } } diff --git a/src/ui/exportghnsdialog.cpp b/src/ui/exportghnsdialog.cpp index 2727577..c54d9cf 100644 --- a/src/ui/exportghnsdialog.cpp +++ b/src/ui/exportghnsdialog.cpp @@ -1,86 +1,85 @@ /* * 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 "core/resourcemanager.h" +#include "core/iresourcerepository.h" #include "core/resources/languageresource.h" #include "core/resources/editablecourseresource.h" #include "core/resources/courseparser.h" #include "core/icourse.h" #include "artikulate_debug.h" #include #include #include #include #include -ExportGhnsDialog::ExportGhnsDialog(ResourceManager *manager) - : m_manager(manager) +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, [=](){ 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); // 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); ui->exportDirectory->setText(dir); }); // add courses to combo box int counter = 0; - foreach (auto *languageRes, manager->languageResources()) { - foreach (auto *courseRes, manager->courseResources(languageRes->language())) { - ui->courseListCombo->insertItem(counter, courseRes->i18nTitle(), - QVariant::fromValue(courseRes)); + for (auto *language : repository->languages()) { + for (auto *course : repository->courses(language)) { + ui->courseListCombo->insertItem(counter, course->i18nTitle(), + QVariant::fromValue(course)); ++counter; } } connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } ExportGhnsDialog::~ExportGhnsDialog() { delete ui; } void ExportGhnsDialog::onExportCourse() { ICourse *res = qobject_cast( ui->courseListCombo->currentData().value()); qCDebug(ARTIKULATE_LOG) << res << "export GHNS file for" << res->i18nTitle(); CourseParser::exportCourseToGhnsPackage(res, ui->exportDirectory->text()); } diff --git a/src/ui/exportghnsdialog.h b/src/ui/exportghnsdialog.h index ae4d8ea..76e86a2 100644 --- a/src/ui/exportghnsdialog.h +++ b/src/ui/exportghnsdialog.h @@ -1,47 +1,46 @@ /* * 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 -class ResourceManager; +class IResourceRepository; class ExportGhnsDialog : public QDialog { Q_OBJECT public: - explicit ExportGhnsDialog(ResourceManager *manager); + explicit ExportGhnsDialog(IResourceRepository *repository); ~ExportGhnsDialog(); public Q_SLOTS: void onExportCourse(); private: Ui::ExportGhnsDialog *ui; - const ResourceManager *m_manager; }; #endif diff --git a/src/ui/resourcesdialogpage.cpp b/src/ui/resourcesdialogpage.cpp index c73ca2d..07edd8e 100644 --- a/src/ui/resourcesdialogpage.cpp +++ b/src/ui/resourcesdialogpage.cpp @@ -1,69 +1,69 @@ /* * 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 "resourcesdialogpage.h" -#include "core/resourcemanager.h" +#include "core/contributorrepository.h" #include "core/language.h" #include "settings.h" #include #include #include #include #include -ResourcesDialogPage::ResourcesDialogPage(ResourceManager *m_resourceManager) +ResourcesDialogPage::ResourcesDialogPage(ContributorRepository *repository) : QWidget(nullptr) - , m_resourceManager(m_resourceManager) + , m_repository(repository) , m_restartNeeded(false) { ui = new Ui::ResourcesDialogPage; ui->setupUi(this); connect(ui->buttonSelectCourseRepository, &QToolButton::clicked, this, [=](){ const QString dir = QFileDialog::getExistingDirectory(this, i18n("Open Repository Directory"), QString(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); ui->kcfg_CourseRepositoryPath->setText(dir); }); } ResourcesDialogPage::~ResourcesDialogPage() { delete ui; } void ResourcesDialogPage::loadSettings() { // setup Ui with stored settings ui->kcfg_CourseRepositoryPath->setText(Settings::courseRepositoryPath()); ui->kcfg_UseCourseRepository->setChecked(Settings::useCourseRepository()); } void ResourcesDialogPage::saveSettings() { // save settings Settings::setUseCourseRepository(ui->kcfg_UseCourseRepository->isChecked()); Settings::setCourseRepositoryPath(ui->kcfg_CourseRepositoryPath->text()); Settings::self()->save(); // reloading resources - m_resourceManager->loadCourseResources(); + m_repository->loadCourseResources(); } diff --git a/src/ui/resourcesdialogpage.h b/src/ui/resourcesdialogpage.h index 50ad2f3..0efa9a1 100644 --- a/src/ui/resourcesdialogpage.h +++ b/src/ui/resourcesdialogpage.h @@ -1,48 +1,48 @@ /* * 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 RESOURCESDIALOGPAGE_H #define RESOURCESDIALOGPAGE_H #include "ui_resourcesdialogpage.h" #include -class ResourceManager; +class ContributorRepository; class Course; class ResourcesDialogPage : public QWidget { Q_OBJECT public: - explicit ResourcesDialogPage(ResourceManager *resourceMgr); + explicit ResourcesDialogPage(ContributorRepository *repository); virtual ~ResourcesDialogPage(); public Q_SLOTS: void saveSettings(); void loadSettings(); private: Ui::ResourcesDialogPage *ui; - ResourceManager *m_resourceManager; + ContributorRepository *m_repository{nullptr}; bool m_restartNeeded; }; #endif