diff --git a/src/core/ieditablecourse.h b/src/core/ieditablecourse.h index c230a06..96531e7 100644 --- a/src/core/ieditablecourse.h +++ b/src/core/ieditablecourse.h @@ -1,83 +1,83 @@ /* * Copyright 2019 Andreas Cord-Landwehr * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef IEDITABLECOURSE_H #define IEDITABLECOURSE_H #include "artikulatecore_export.h" #include "icourse.h" #include #include class QString; class ILanguage; class IEditableUnit; class IPhrase; class ARTIKULATECORE_EXPORT IEditableCourse : public ICourse { Q_OBJECT Q_INTERFACES(ICourse) public: virtual ~IEditableCourse() = default; virtual void setId(QString id) = 0; virtual void setForeignId(QString foreignId) = 0; virtual void setTitle(QString title) = 0; virtual void setI18nTitle(QString title) = 0; virtual void setDescription(QString description) = 0; virtual void setLanguage(std::shared_ptr language) = 0; virtual std::shared_ptr addUnit(std::shared_ptr unit) = 0; Q_INVOKABLE virtual bool createPhraseAfter(IPhrase *phrase) = 0; Q_INVOKABLE virtual bool deletePhrase(IPhrase *phrase) = 0; /** * @brief Export course to specified file. * @param filePath the absolute path to the export file * @return true of export finished without errors */ virtual bool exportToFile(const QUrl &filePath) const = 0; /** * @brief store editable course in file and set modified to false * @return true if no errors occurred */ - virtual bool sync() = 0; + Q_INVOKABLE virtual bool sync() = 0; /** * @brief Update course from skeleton * This method imports all units and phrases from the specified skeleton * * @param skeleton */ virtual void updateFrom(std::shared_ptr skeleton) = 0; virtual bool isModified() const = 0; virtual std::shared_ptr self() const = 0; Q_SIGNALS: void unitChanged(std::shared_ptr unit); protected: IEditableCourse() : ICourse() { } }; Q_DECLARE_INTERFACE(IEditableCourse, "com.kde.artikulate.IEditableCourse/1.0") #endif // EDITABLECOURSE_H diff --git a/src/mainwindow_editor.cpp b/src/mainwindow_editor.cpp index ae876fd..3156571 100644 --- a/src/mainwindow_editor.cpp +++ b/src/mainwindow_editor.cpp @@ -1,156 +1,153 @@ /* * 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 "artikulate_debug.h" #include "core/editorsession.h" #include "core/resources/courseresource.h" #include "libsound/src/outputdevicecontroller.h" #include "models/languagemodel.h" #include "settings.h" #include "ui/exportghnsdialog.h" #include "ui/sounddevicedialogpage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace LearnerProfile; MainWindowEditor::MainWindowEditor(ContributorRepository *repository) : m_repository(repository) , m_editorSession(new EditorSession()) { rootContext()->setContextObject(new KLocalizedContext(this)); rootContext()->setContextProperty(QStringLiteral("g_repository"), m_repository); rootContext()->setContextProperty(QStringLiteral("g_editorSession"), m_editorSession); rootContext()->setContextProperty(QStringLiteral("g_artikulateAboutData"), QVariant::fromValue(KAboutData::applicationData())); m_repository->setStorageLocation(QUrl::fromLocalFile(Settings::courseRepositoryPath())); m_editorSession->setRepository(m_repository); // load saved sound settings OutputDeviceController::self().setVolume(Settings::audioOutputVolume()); m_repository->reloadCourses(); // create menu setupActions(); // set starting screen load(QUrl(QStringLiteral("qrc:/artikulate/qml/Editor.qml"))); - - // QAction *newAct = KStandardAction::save(this, SLOT(save()), actionCollection()); - // actionCollection()->addAction(QStringLiteral("save"), newAct); } MainWindowEditor::~MainWindowEditor() { // save current settings for case of closing Settings::self()->save(); } ContributorRepository *MainWindowEditor::resourceRepository() const { return m_repository; } void MainWindowEditor::setupActions() { // QAction *settingsAction = new QAction(i18nc("@item:inmenu", "Configure Artikulate"), this); // connect(settingsAction, &QAction::triggered, this, &MainWindowEditor::showSettingsDialog); // actionCollection()->addAction(QStringLiteral("settings"), settingsAction); // settingsAction->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); // QAction *exportAction = new QAction(i18nc("@item:inmenu", "Export GHNS Files"), this); // connect(exportAction, &QAction::triggered, this, [=]() { // QPointer dialog = new ExportGhnsDialog(m_repository); // dialog->exec(); // }); // actionCollection()->addAction(QStringLiteral("export_ghns"), exportAction); // exportAction->setIcon(QIcon::fromTheme(QStringLiteral("document-export"))); // KStandardAction::quit(this, SLOT(quit()), actionCollection()); } void MainWindowEditor::showSettingsDialog() { if (KConfigDialog::showDialog(QStringLiteral("settings"))) { return; } QPointer dialog = new KConfigDialog(nullptr, QStringLiteral("settings"), Settings::self()); SoundDeviceDialogPage *soundDialog = new SoundDeviceDialogPage(); soundDialog->loadSettings(); dialog->addPage(soundDialog, i18nc("@item:inmenu", "Sound Devices"), QStringLiteral("audio-headset"), i18nc("@title:tab", "Sound Device Settings"), true); connect(dialog.data(), &QDialog::accepted, soundDialog, &SoundDeviceDialogPage::saveSettings); dialog->exec(); } void MainWindowEditor::save() { m_repository->sync(); } void MainWindowEditor::quit() { // if (queryClose()) { // qApp->quit(); // } } // bool MainWindowEditor::queryClose() //{ // if (!m_repository->modified()) { // return true; // } // int result = KMessageBox::warningYesNoCancel(nullptr, i18nc("@info", // "The currently open course contains unsaved changes. Do you want to save them?")); // switch(result) { // case KMessageBox::Yes: // m_repository->sync(); // return true; // case KMessageBox::No: // return true; // default: // return false; // } //} diff --git a/src/qml/EditorDrawer.qml b/src/qml/EditorDrawer.qml index 362d30e..49630d5 100644 --- a/src/qml/EditorDrawer.qml +++ b/src/qml/EditorDrawer.qml @@ -1,159 +1,170 @@ /* * Copyright 2018 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.Layouts 1.3 import QtQuick.Controls 2.0 as QQC2 import org.kde.kirigami 2.7 as Kirigami import artikulate 1.0 Kirigami.GlobalDrawer { id: root title: "Editor" titleIcon: "artikulate" resetMenuOnTriggered: false bottomPadding: 0 property QtObject pageStack // enforce drawer always to be open modal: false handleVisible: false topContent: [ ColumnLayout { spacing: 0 Layout.fillWidth: true Layout.leftMargin: -root.leftPadding Layout.rightMargin: -root.rightPadding ActionListItem { action: Kirigami.Action { text: i18n("Courses") iconName: "artikulate" onTriggered: { root.pageStack.clear(); root.pageStack.push(editorCourseSelectionPage); root.pageStack.push(editorSkeletonSelectionPage); } } } ActionListItem { action: Kirigami.Action { text: i18n("Repository") iconName: "folder-sync" onTriggered: { root.pageStack.clear(); root.pageStack.push(repositoryPageComponent); } } } Kirigami.Separator { Layout.fillWidth: true } ActionListItem { action: Kirigami.Action { text: i18n("Course Configuration") iconName: "document-properties" enabled: g_editorSession.course !== null onTriggered: { root.pageStack.clear(); root.pageStack.push(courseConfigurationPageComponent); } } } } ] // ordinary Kirigami actions are filled from training units/phrases actions: trainingActions.actions DrawerTrainingActions { id: trainingActions session: g_editorSession onTriggerPhraseView: { root.pageStack.clear(); root.pageStack.push(editCoursePageComponent); } } //TODO integrate again // [ // Kirigami.Action { // text: i18n("Help") // iconName: "help-about" // Kirigami.Action { // text: i18n("Artikulate Handbook") // iconName: "help-contents" // onTriggered: { // triggerAction("help_contents"); // globalDrawer.resetMenu(); // } // } // Kirigami.Action { // text: i18n("Report Bug") // iconName: "tools-report-bug" // onTriggered: { // triggerAction("help_report_bug"); // globalDrawer.resetMenu(); // } // } // Kirigami.Action { // text: i18n("About KDE") // iconName: "help-about" // onTriggered: { // triggerAction("help_about_kde") // globalDrawer.resetMenu(); // } // } // } // ] ColumnLayout { spacing: 0 Layout.fillWidth: true Layout.leftMargin: -root.leftPadding Layout.rightMargin: -root.rightPadding + ActionListItem { + action: Kirigami.Action { + text: i18n("Save") + iconName: "document-save" + enabled: g_editorSession.course !== null + onTriggered: { + g_editorSession.course.sync() + } + } + } + Kirigami.Separator { Layout.fillWidth: true } //TODO planned but not implemented // ActionListItem { // action: Kirigami.Action { // text: i18n("Upload Training") // iconName: "get-hot-new-stuff" // onTriggered: { // root.pageStack.pop(); // root.pageStack.push(downloadPageComponent); // } // } // } ActionListItem { action: Kirigami.Action { text: i18n("About") iconName: "help-about" onTriggered: { root.pageStack.pop(); root.pageStack.push(aboutPageComponent); } } } } }