Commit 6487111d authored by Leander Schulten's avatar Leander Schulten

UX: Show popup when the loading of the settings file failed. In the Popup you...

UX: Show popup when the loading of the settings file failed. In the Popup you can choose a other file or reload the currently selected file. This popup does not handle the case where no settings file is selected, only when the loading fails
parent 0808c546
Pipeline #199377 passed with stage
in 5 minutes and 50 seconds
......@@ -53,6 +53,7 @@ SOURCES += \
modules/dmxconsumer.cpp \
modules/ledconsumer.cpp \
scanner.cpp \
settingsfilewrapper.cpp \
slideshow.cpp \
system_error_handler.cpp \
test/testloopprogramm.cpp \
......@@ -125,6 +126,7 @@ HEADERS += \
modules/ledconsumer.h \
modules/scanner.hpp \
scanner.h \
settingsfilewrapper.h \
slideshow.h \
system_error_handler.h \
updater.h \
......
......@@ -90,7 +90,17 @@ std::pair<std::function<void()>, QString> loadData(const QByteArray &data) {
QJsonParseError error{};
auto doc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
return {{}, "Failed to parse settings file: " + error.errorString() + " at position " + QString::number(error.offset)};
// compute line and column
int line = 1;
auto lastNewLine = data.cbegin();
for (auto i = data.cbegin(); i != data.cbegin() + error.offset; ++i) {
if (*i == '\n') {
++line;
lastNewLine = i;
}
}
int column = QString::fromUtf8(lastNewLine, data.cbegin() + error.offset - lastNewLine).length();
return {{}, "Failed to parse settings file: " + error.errorString() + " at position " + QString::number(error.offset) + ", Ln " + QString::number(line) + ", Col " + QString::number(column)};
}
const auto o = doc.object();
for (const auto e : o[QStringLiteral("DevicePrototypes")].toArray()) {
......
......@@ -3,6 +3,7 @@
#include "errornotifier.h"
#include "modelmanager.h"
#include "settings.h"
#include "settingsfilewrapper.h"
#include "slideshow.h"
#include "sortedmodelview.h"
#include "updater.h"
......@@ -250,8 +251,9 @@ int main(int argc, char *argv[]) {
qmlRegisterType<Settings>("custom.licht", 1, 0, "PopupBackground");
qRegisterMetaType<DMXChannelFilter::Operation>("Operation");
qmlRegisterUncreatableType<UserManagment>("custom.licht",1,0,"Permission",QStringLiteral("Singletone in c++"));
qmlRegisterUncreatableMetaObject(Updater::staticMetaObject,"custom.licht",1,0,"UpdaterState",QStringLiteral("Enum in c++"));
qmlRegisterUncreatableMetaObject(ControlItemData::staticMetaObject,"custom.licht",1,0,"ControlType",QStringLiteral("Enum in c++"));
qmlRegisterUncreatableMetaObject(Updater::staticMetaObject, "custom.licht", 1, 0, "UpdaterState", QStringLiteral("Enum in c++"));
qmlRegisterUncreatableMetaObject(ControlItemData::staticMetaObject, "custom.licht", 1, 0, "ControlType", QStringLiteral("Enum in c++"));
qmlRegisterUncreatableType<SettingsFileWrapper>("custom.licht", 1, 0, "SettingsFileStatus", QStringLiteral("Enum in c++"));
qRegisterMetaType<UserManagment::Permission>("Permission");
qRegisterMetaType<Modules::detail::PropertyInformation::Type>("Type");
qRegisterMetaType<Modules::ValueType>("ValueType");
......@@ -266,6 +268,7 @@ int main(int argc, char *argv[]) {
// Load Settings and ApplicationData
Settings::setLocalSettingFile(QFileInfo(QStringLiteral("settings.ini")));
Settings settings;
SettingsFileWrapper settingsFileWrapper(settings);
RemoteVolume remoteVolume(settings);
if (settings.isStartupVolumeEnabled()) {
......@@ -283,11 +286,15 @@ int main(int argc, char *argv[]) {
QString error;
std::tie(after, error) = ApplicationData::loadData(file);
if (!error.isEmpty()) {
ErrorNotifier::showError(error);
settingsFileWrapper.setErrorMessage(error);
settingsFileWrapper.setStatus(SettingsFileWrapper::LoadingFailed);
} else {
settingsFileWrapper.setStatus(SettingsFileWrapper::Loaded);
}
} else {
ErrorNotifier::showError(QStringLiteral("No settings file found! The Lichtsteuerung starts wihout content."));
settingsFileWrapper.setStatus(SettingsFileWrapper::NoFile);
}
// nachdem die Benutzer geladen wurden, auto login durchführen
UserManagment::get()->autoLoginUser();
......@@ -329,7 +336,10 @@ int main(int argc, char *argv[]) {
CatchingErrorApplication::connect(&app, &QGuiApplication::aboutToQuit, [&]() {
Modules::ModuleManager::singletone()->controller().stop();
Audio::AudioCaptureManager::get().stopCapturingAndWait();
ApplicationData::saveData(settings.getJsonSettingsFileSavePath());
// if status is not SettingsFileWrapper::Loaded, the loading of the data failed and we should not write back an emtpy file
if (settingsFileWrapper.getStatus() == SettingsFileWrapper::Loaded) {
ApplicationData::saveData(settings.getJsonSettingsFileSavePath());
}
Driver::stopAndUnloadDriver();
if (updater.getState() == Updater::ReadyToInstall) {
updater.runUpdateInstaller();
......@@ -344,7 +354,12 @@ int main(int argc, char *argv[]) {
Driver::getCurrentDriver()->setWaitTime(std::chrono::milliseconds(settings.getUpdatePauseInMs()));
}
});
Settings::connect(&settings, &Settings::saveAs, [&](const auto &path) { ApplicationData::saveData(path); });
Settings::connect(&settings, &Settings::saveAs, [&](const auto &path) {
// if status is not SettingsFileWrapper::Loaded, the loading of the data failed and we should not write back an emtpy file
if (settingsFileWrapper.getStatus() == SettingsFileWrapper::Loaded) {
ApplicationData::saveData(path);
}
});
Modules::ModuleManager::singletone()->loadAllModulesInDir(settings.getModuleDirPath());
Settings::connect(&settings, &Settings::moduleDirPathChanged, [&]() { Modules::ModuleManager::singletone()->loadAllModulesInDir(settings.getModuleDirPath()); });
......@@ -372,6 +387,7 @@ int main(int argc, char *argv[]) {
engine.rootContext()->setContextProperty(QStringLiteral("dmxOutputValues"),&Driver::dmxValueModel);
engine.rootContext()->setContextProperty(QStringLiteral("AudioManager"), &Audio::AudioCaptureManager::get());
engine.rootContext()->setContextProperty(QStringLiteral("SlideShow"), &SlideShow::get());
engine.rootContext()->setContextProperty(QStringLiteral("SettingsFile"), &settingsFileWrapper);
engine.rootContext()->setContextProperty(QStringLiteral("System"), &SystemVolume::get());
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
engine.load(QUrl(QStringLiteral("qrc:/qml/SlideShowWindow.qml")));
......
......@@ -314,4 +314,84 @@ ApplicationWindow {
visible: ErrorNotifier.errorMessage.length !== 0
}
Popup {
Overlay.modal: ModalPopupBackground{}
closePolicy: Popup.NoAutoClose
y: 70
x: (parent.width - width) / 2
modal: true
visible: SettingsFile.status === SettingsFileStatus.LoadingFailed
onVisibleChanged: {
if (visible) {
fileDialogLoader.source = "components/SystemFileDialog.qml"
}
}
contentItem: ColumnLayout {
Label {
font.pointSize: 15
font.bold: true
text: "Failed to load settings file"
}
Label {
id: fontReference
text: SettingsFile.errorMessage
Layout.bottomMargin: 5
Layout.maximumWidth: 500
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
}
TextInput {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.leftMargin: 1
Layout.rightMargin: 2
clip: true
color: Material.foreground
selectionColor: Material.textSelectionColor
font: fontReference.font
text: Settings.jsonSettingsFilePath
selectByMouse: true
readOnly: true
}
GridLayout {
columns: 2
rowSpacing: -5
Button {
text: "Open file in default editor"
Layout.fillWidth: true
flat: true
onClicked: SettingsFile.openFileInDefaultEditor();
}
Button {
text: "Open folder where file is"
Layout.fillWidth: true
flat: true
onClicked: SettingsFile.openFileExplorerAtFile();
}
Button {
text: "Reload selected settings file"
Layout.fillWidth: true
onClicked: SettingsFile.reload();
}
Button {
text: "Load an other settings file"
Layout.fillWidth: true
onClicked: fileDialogLoader.item.openAt(Settings.jsonSettingsFilePath, false)
}
}
}
Loader {
asynchronous: true
id: fileDialogLoader
onStatusChanged: {
if (status === Loader.Ready) {
item.callback = path => {
SettingsFile.loadFile(path);
};
}
}
}
}
}
#include "settingsfilewrapper.h"
#include "applicationdata.h"
#include "errornotifier.h"
#include "usermanagment.h"
#include <QDesktopServices>
#include <QUrl>
void SettingsFileWrapper::setStatus(SettingsFileWrapper::Status status) {
if (this->status != status) {
this->status = status;
emit statusChanged();
}
}
void SettingsFileWrapper::setErrorMessage(const QString &errorMessage) {
if (this->errorMessage != errorMessage) {
this->errorMessage = errorMessage;
emit errorMessageChanged();
}
}
void SettingsFileWrapper::loadFile(const QString &filepath) {
Q_ASSERT(status != Loaded);
settings.setJsonSettingsFilePath(filepath);
auto [after, error] = ApplicationData::loadData(filepath);
if (error.isEmpty()) {
after();
UserManagment::get()->autoLoginUser();
setStatus(Loaded);
} else {
setErrorMessage(error);
setStatus(LoadingFailed);
}
}
bool SettingsFileWrapper::openFileInDefaultEditor() {
return QDesktopServices::openUrl(QUrl::fromLocalFile(settings.getJsonSettingsFilePath()));
}
void SettingsFileWrapper::openFileExplorerAtFile() {
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(settings.getJsonSettingsFilePath()).path()));
}
#ifndef SETTINGSFILEWRAPPER_H
#define SETTINGSFILEWRAPPER_H
#include "settings.h"
#include <QObject>
/**
* @brief The SettingsFileWrapper class wrapps the status of the settings file for QML
*/
class SettingsFileWrapper : public QObject {
Q_OBJECT
public:
enum Status { Loaded, NoFile, LoadingFailed, NotLoaded };
Q_ENUM(Status)
private:
Settings &settings;
QString errorMessage;
Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged)
Q_PROPERTY(Status status READ getStatus NOTIFY statusChanged)
Status status = NotLoaded;
public:
explicit SettingsFileWrapper(Settings &settings) : settings(settings) {}
[[nodiscard]] Status getStatus() const { return status; }
void setStatus(Status status);
[[nodiscard]] QString getErrorMessage() const { return errorMessage; }
void setErrorMessage(const QString &errorMessage);
Q_INVOKABLE void loadFile(const QString &filepath);
Q_INVOKABLE void reload() { loadFile(settings.getJsonSettingsFilePath()); }
Q_INVOKABLE bool openFileInDefaultEditor();
Q_INVOKABLE void openFileExplorerAtFile();
signals:
void statusChanged();
void errorMessageChanged();
};
#endif // SETTINGSFILEWRAPPER_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment