From 831bf87d0c171d4e1183e487724e3bf04ebab2ff Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 16 Sep 2020 07:11:50 -0600 Subject: [PATCH] Improved exceptions and added error message dialog UI --- apps/OpenSpace/ext/launcher/CMakeLists.txt | 3 + apps/OpenSpace/ext/launcher/include/assets.h | 2 +- .../ext/launcher/include/deltatimes.h | 5 +- .../ext/launcher/include/errordialog.h | 29 +++++++ .../ext/launcher/include/profileedit.h | 27 ++---- .../ext/launcher/include/ui_errordialog.h | 66 ++++++++++++++ apps/OpenSpace/ext/launcher/src/assets.cpp | 2 +- .../OpenSpace/ext/launcher/src/deltatimes.cpp | 24 +++-- .../ext/launcher/src/errordialog.cpp | 23 +++++ .../OpenSpace/ext/launcher/src/errordialog.ui | 87 +++++++++++++++++++ .../ext/launcher/src/launcherwindow.cpp | 12 +-- .../ext/launcher/src/profileedit.cpp | 64 ++++++++++++-- include/openspace/scene/profile.h | 12 +++ src/scene/profile.cpp | 85 ++++++++---------- 14 files changed, 345 insertions(+), 96 deletions(-) create mode 100644 apps/OpenSpace/ext/launcher/include/errordialog.h create mode 100644 apps/OpenSpace/ext/launcher/include/ui_errordialog.h create mode 100644 apps/OpenSpace/ext/launcher/src/errordialog.cpp create mode 100644 apps/OpenSpace/ext/launcher/src/errordialog.ui diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index 2efd5b342b..2eaef39f81 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -27,6 +27,7 @@ set(HEADER_FILES include/assettreemodel.h include/camera.h include/deltatimes.h + include/errordialog.h include/filesystemaccess.h include/keybindings.h include/launcherwindow.h @@ -40,6 +41,7 @@ set(HEADER_FILES include/ui_assets.h include/ui_camera.h include/ui_deltatimes.h + include/ui_errordialog.h include/ui_keybindings.h include/ui_launcherwindow.h include/ui_marknodes.h @@ -57,6 +59,7 @@ set(SOURCE_FILES src/assettreemodel.cpp src/camera.cpp src/deltatimes.cpp + src/errordialog.cpp src/filesystemaccess.cpp src/keybindings.cpp src/launcherwindow.cpp diff --git a/apps/OpenSpace/ext/launcher/include/assets.h b/apps/OpenSpace/ext/launcher/include/assets.h index 15ed288aa9..11c0fafc0e 100644 --- a/apps/OpenSpace/ext/launcher/include/assets.h +++ b/apps/OpenSpace/ext/launcher/include/assets.h @@ -23,7 +23,7 @@ public slots: void parseSelections(); public: - explicit assets(openspace::Profile* imported, std::string& reportAssets, + explicit assets(openspace::Profile* imported, const std::string reportAssets, QWidget *parent = nullptr); ~assets(); std::string createTextSummary(); diff --git a/apps/OpenSpace/ext/launcher/include/deltatimes.h b/apps/OpenSpace/ext/launcher/include/deltatimes.h index f951aacb0c..53127f30fd 100644 --- a/apps/OpenSpace/ext/launcher/include/deltatimes.h +++ b/apps/OpenSpace/ext/launcher/include/deltatimes.h @@ -25,8 +25,11 @@ struct DeltaTimes { std::vector _times; DeltaTimes() { _times.resize(sizeof(_defaultDeltaTimes)/sizeof(double)); + zeroValues(); }; DeltaTimes(std::vector dt) { + _times.resize(sizeof(_defaultDeltaTimes)/sizeof(double)); + zeroValues(); _times = dt; }; void loadValues(std::vector& dt) { @@ -39,7 +42,7 @@ struct DeltaTimes { return std::distance(_times.begin(), it); }; size_t totalSize() { - return sizeof(_defaultDeltaTimes) / sizeof(double); + return (sizeof(_defaultDeltaTimes) / sizeof(double)); } void zeroValues() { for (size_t i = 0; i < _times.size(); ++i) { diff --git a/apps/OpenSpace/ext/launcher/include/errordialog.h b/apps/OpenSpace/ext/launcher/include/errordialog.h new file mode 100644 index 0000000000..a68a2373d2 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/include/errordialog.h @@ -0,0 +1,29 @@ +#ifndef ERRORDIALOG_H +#define ERRORDIALOG_H + +#include +#include +#include +#include "ui_errordialog.h" + +namespace Ui { +class errordialog; +} + +class errordialog : public QDialog +{ + Q_OBJECT + +public slots: + //void accept(); + +public: + explicit errordialog(QString message, QWidget *parent = nullptr); + ~errordialog(); + +private: + Ui::errordialog *ui; + QWidget* _parent; +}; + +#endif // ERRORDIALOG_H diff --git a/apps/OpenSpace/ext/launcher/include/profileedit.h b/apps/OpenSpace/ext/launcher/include/profileedit.h index e8d6fd8e1b..ff29780d8a 100644 --- a/apps/OpenSpace/ext/launcher/include/profileedit.h +++ b/apps/OpenSpace/ext/launcher/include/profileedit.h @@ -15,6 +15,7 @@ #include "marknodes.h" #include "ostime.h" #include +#include QT_BEGIN_NAMESPACE namespace Ui { @@ -22,20 +23,6 @@ class ProfileEdit; } QT_END_NAMESPACE -/*struct ProfileBlock { - openspace::Profile::Meta& _metaData; - std::vector& _moduleData; - std::vector& _assetData; - std::string& _reportAssetsInFilesystem; - std::vector& _propsData; - std::vector& _keybindingsData; - DeltaTimes& _deltaTimesData; - openspace::Profile::Time& _timeData; - openspace::Profile::CameraType& _cameraData; - std::vector& _markNodesData; - std::string& _addedScriptsData; -};*/ - class ProfileEdit : public QDialog { Q_OBJECT @@ -51,14 +38,17 @@ public slots: void openDeltaTimes(); void openCamera(); void openMarkNodes(); + void cancel(); + void approved(); public: - explicit ProfileEdit(std::string filename, std::string reportedAssets, QWidget *parent = nullptr); + explicit ProfileEdit(std::string filename, const std::string reportedAssets, QWidget *parent = nullptr); ~ProfileEdit(); - //void setProfileName(QString profileToSet); + void setProfileName(QString profileToSet); private: - void loadProfileFromFile(std::string filename); + bool loadProfileFromFile(std::string filename); + void displayProfileParseErrorDialogThenQuit(std::string msg); void initSummaryTextForEachCategory(); QString summarizeText_meta(); QString summarizeText_modules(); @@ -73,6 +63,7 @@ private: Ui::ProfileEdit *ui; QWidget* _parent; + errordialog* _myDialog; meta* _meta; properties* _properties; osmodules* _modules; @@ -87,7 +78,7 @@ private: //ProfileBlock _pData; openspace::Profile* _pData = nullptr; std::vector _content; - std::string& _reportedAssets; + const std::string _reportedAssets; }; #endif // PROFILEEDIT_H diff --git a/apps/OpenSpace/ext/launcher/include/ui_errordialog.h b/apps/OpenSpace/ext/launcher/include/ui_errordialog.h new file mode 100644 index 0000000000..bc075b79da --- /dev/null +++ b/apps/OpenSpace/ext/launcher/include/ui_errordialog.h @@ -0,0 +1,66 @@ +/******************************************************************************** +** Form generated from reading UI file 'errordialog.ui' +** +** Created by: Qt User Interface Compiler version 5.15.0 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_ERRORDIALOG_H +#define UI_ERRORDIALOG_H + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_errordialog +{ +public: + QDialogButtonBox *buttonBox; + QLabel *label; + + void setupUi(QDialog *errordialog) + { + if (errordialog->objectName().isEmpty()) + errordialog->setObjectName(QString::fromUtf8("errordialog")); + errordialog->resize(400, 181); + buttonBox = new QDialogButtonBox(errordialog); + buttonBox->setObjectName(QString::fromUtf8("buttonBox")); + buttonBox->setGeometry(QRect(140, 120, 91, 32)); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Ok); + label = new QLabel(errordialog); + label->setObjectName(QString::fromUtf8("label")); + label->setGeometry(QRect(20, 10, 360, 100)); + QFont font; + font.setFamily(QString::fromUtf8("Arial")); + font.setPointSize(12); + label->setFont(font); + label->setWordWrap(true); + + retranslateUi(errordialog); + QObject::connect(buttonBox, SIGNAL(accepted()), errordialog, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), errordialog, SLOT(reject())); + + QMetaObject::connectSlotsByName(errordialog); + } // setupUi + + void retranslateUi(QDialog *errordialog) + { + errordialog->setWindowTitle(QCoreApplication::translate("errordialog", "Profile Format Error", nullptr)); + label->setText(QCoreApplication::translate("errordialog", "TextLabel", nullptr)); + } // retranslateUi + +}; + +namespace Ui { + class errordialog: public Ui_errordialog {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_ERRORDIALOG_H diff --git a/apps/OpenSpace/ext/launcher/src/assets.cpp b/apps/OpenSpace/ext/launcher/src/assets.cpp index 96c46f6852..6a0f3761d6 100644 --- a/apps/OpenSpace/ext/launcher/src/assets.cpp +++ b/apps/OpenSpace/ext/launcher/src/assets.cpp @@ -7,7 +7,7 @@ #include #include -assets::assets(openspace::Profile* imported, std::string& reportAssets, QWidget *parent) +assets::assets(openspace::Profile* imported, const std::string reportAssets, QWidget *parent) : QDialog(parent) , ui(new Ui::assets) , _imported(imported) diff --git a/apps/OpenSpace/ext/launcher/src/deltatimes.cpp b/apps/OpenSpace/ext/launcher/src/deltatimes.cpp index 4bdbf7756f..4d0e423f85 100644 --- a/apps/OpenSpace/ext/launcher/src/deltatimes.cpp +++ b/apps/OpenSpace/ext/launcher/src/deltatimes.cpp @@ -1,6 +1,7 @@ #include "deltatimes.h" #include "./ui_deltatimes.h" #include +#include deltaTimes::deltaTimes(openspace::Profile* imported, QWidget *parent) : QDialog(parent) @@ -10,7 +11,7 @@ deltaTimes::deltaTimes(openspace::Profile* imported, QWidget *parent) { ui->setupUi(this); - for (size_t d = 0; d < _data.totalSize(); ++d) { + for (size_t d = 0; d < _data.size(); ++d) { QString summary = createSummaryForDeltaTime(d, _data._times.at(d), true); _deltaListItems.push_back(new QListWidgetItem(summary)); ui->listWidget->addItem(_deltaListItems[d]); @@ -69,6 +70,9 @@ void deltaTimes::listItemSelected() { } int deltaTimes::lastSelectableItem() { + if (_data.size() == 0) { + return 0; + } int i; for (i = _data.size() - 1; i >= 0; --i) { if (_data._times.at(i) != 0) { @@ -112,11 +116,19 @@ QString deltaTimes::checkForTimeDescription(int intervalIndex, double value) { void deltaTimes::saveDeltaTimeValue() { QListWidgetItem *item = ui->listWidget->currentItem(); - int index = ui->listWidget->row(item); - if (isNumericalValue(ui->line_seconds) && index <= lastSelectableItem() + 1) { - _data._times.at(index) = ui->line_seconds->text().toDouble(); - QString summary = createSummaryForDeltaTime(index, _data._times.at(index), true); - _deltaListItems.at(index)->setText(summary); + if (item != nullptr) { + int index = ui->listWidget->row(item); + if (isNumericalValue(ui->line_seconds) && index <= lastSelectableItem() + 1) { + _data._times.at(index) = ui->line_seconds->text().toDouble(); + QString summary = createSummaryForDeltaTime(index, _data._times.at(index), true); + _deltaListItems.at(index)->setText(summary); + } + } + else if (_data.size() == 0) { + _data._times.at(0) = ui->line_seconds->text().toDouble(); + QString summary = createSummaryForDeltaTime(0, _data._times.at(0), true); + _deltaListItems.push_back(new QListWidgetItem(summary)); + ui->listWidget->addItem(_deltaListItems[0]); } } diff --git a/apps/OpenSpace/ext/launcher/src/errordialog.cpp b/apps/OpenSpace/ext/launcher/src/errordialog.cpp new file mode 100644 index 0000000000..77895a424d --- /dev/null +++ b/apps/OpenSpace/ext/launcher/src/errordialog.cpp @@ -0,0 +1,23 @@ +#include "errordialog.h" +#include "ui_errordialog.h" +#include +#include +#include + + +errordialog::errordialog(QString message, QWidget *parent) + : QDialog(parent) + , ui(new Ui::errordialog) +{ + ui->setupUi(this); + ui->label->setText(message); + //connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(cancel())); +} + +errordialog::~errordialog() { + delete ui; +} + +//void errordialog::accept() { +// reject(); +//} diff --git a/apps/OpenSpace/ext/launcher/src/errordialog.ui b/apps/OpenSpace/ext/launcher/src/errordialog.ui new file mode 100644 index 0000000000..1c6ea2c796 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/src/errordialog.ui @@ -0,0 +1,87 @@ + + + errordialog + + + + 0 + 0 + 400 + 181 + + + + Profile Format Error + + + + + 140 + 120 + 91 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + 60 + 30 + 261 + 41 + + + + + Arial + 12 + + + + TextLabel + + + + + + + buttonBox + accepted() + errordialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + errordialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp index ef7ee062eb..5c1d91a7c0 100644 --- a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp +++ b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp @@ -15,17 +15,6 @@ LauncherWindow::LauncherWindow(std::string basePath, QWidget *parent) , _filesystemAccess(".asset", {"scene", "global", "customization", "examples"}, true, true) , _basePath(QString::fromUtf8(basePath.c_str())) - /*, _pData({_metaData, - _moduleData, - _assetData, - _reportAssetsInFilesystem, - _propsData, - _keybindingsData, - _deltaTimesData, - _timeData, - _cameraData, - _markNodesData, - _addedScriptsData})*/ { ui->setupUi(this); QString logoPath = _basePath + "/data/openspace-horiz-logo.png"; @@ -78,6 +67,7 @@ void LauncherWindow::openWindow_edit() { editProfilePath += profileToSet.toUtf8().constData(); editProfilePath += ".profile"; myEditorWindow = new ProfileEdit(editProfilePath, _reportAssetsInFilesystem); + myEditorWindow->setProfileName(profileToSet); myEditorWindow->exec(); } diff --git a/apps/OpenSpace/ext/launcher/src/profileedit.cpp b/apps/OpenSpace/ext/launcher/src/profileedit.cpp index ce44540b13..7e002cd12d 100644 --- a/apps/OpenSpace/ext/launcher/src/profileedit.cpp +++ b/apps/OpenSpace/ext/launcher/src/profileedit.cpp @@ -6,7 +6,7 @@ template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; -ProfileEdit::ProfileEdit(std::string filename, std::string reportedAssets, QWidget *parent) +ProfileEdit::ProfileEdit(std::string filename, const std::string reportedAssets, QWidget *parent) : QDialog(parent) , ui(new Ui::ProfileEdit) , _reportedAssets(reportedAssets) @@ -15,7 +15,6 @@ ProfileEdit::ProfileEdit(std::string filename, std::string reportedAssets, QWidg loadProfileFromFile(filename); initSummaryTextForEachCategory(); - connect(ui->edit_meta, SIGNAL(clicked()), this, SLOT(openMeta())); connect(ui->edit_properties, SIGNAL(clicked()), this, SLOT(openProperties())); connect(ui->edit_modules, SIGNAL(clicked()), this, SLOT(openModules())); @@ -26,6 +25,8 @@ ProfileEdit::ProfileEdit(std::string filename, std::string reportedAssets, QWidg connect(ui->edit_deltatimes, SIGNAL(clicked()), this, SLOT(openDeltaTimes())); connect(ui->edit_camera, SIGNAL(clicked()), this, SLOT(openCamera())); connect(ui->edit_marknodes, SIGNAL(clicked()), this, SLOT(openMarkNodes())); + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(approved())); + connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(cancel())); } ProfileEdit::~ProfileEdit() { @@ -33,7 +34,7 @@ ProfileEdit::~ProfileEdit() { delete _pData; } -void ProfileEdit::loadProfileFromFile(std::string filename) { +bool ProfileEdit::loadProfileFromFile(std::string filename) { if (filename.length() > 0) { std::ifstream inFile; try { @@ -41,16 +42,53 @@ void ProfileEdit::loadProfileFromFile(std::string filename) { } catch (const std::ifstream::failure& e) { throw ghoul::RuntimeError(fmt::format( - "Exception opening profile file for read: {} ({})", - filename, e.what()) - ); + "Exception opening {} profile for read: ({})", + filename, + e.what() + )); } std::string line; while (std::getline(inFile, line)) { _content.push_back(std::move(line)); } } - _pData = new openspace::Profile(_content); + try { + _pData = new openspace::Profile(_content); + } + catch (const ghoul::MissingCaseException& e) { + displayProfileParseErrorDialogThenQuit(fmt::format( + "Missing case exception in {}: {}", + filename, + e.what() + )); + return false; + } + catch (const openspace::Profile::ParsingError& e) { + displayProfileParseErrorDialogThenQuit(fmt::format( + "ParsingError exception in {}: {}, {}", + filename, + e.component, + e.message + )); + return false; + } + catch (const ghoul::RuntimeError& e) { + displayProfileParseErrorDialogThenQuit(fmt::format( + "RuntimeError exception in {}, component {}: {}", + filename, + e.component, + e.message + )); + return false; + } + return true; +} + +void ProfileEdit::displayProfileParseErrorDialogThenQuit(std::string msg) { + //New instance of info dialog window + _myDialog = new errordialog(QString(msg.c_str())); + _myDialog->exec(); + cancel(); } void ProfileEdit::initSummaryTextForEachCategory() { @@ -85,9 +123,9 @@ void ProfileEdit::initSummaryTextForEachCategory() { ui->text_additionalscripts->setReadOnly(true); } -/*void ProfileEdit::setProfileName(QString profileToSet) { +void ProfileEdit::setProfileName(QString profileToSet) { ui->line_profile->setText(profileToSet); -}*/ +} void ProfileEdit::openMeta() { if (_pData) { @@ -343,3 +381,11 @@ QString ProfileEdit::summarizeText_markNodes() { } return results; } + +void ProfileEdit::cancel() { + reject(); + rejected(); +} + +void ProfileEdit::approved() { +} diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 0b055a2b6f..fb65ef038e 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -109,6 +109,18 @@ public: std::optional altitude; }; using CameraType = std::variant; + struct ParsingError : public ghoul::RuntimeError { + explicit ParsingError(std::string msg) + : ghoul::RuntimeError(std::move(msg), "profileFile") + {} + + ParsingError(unsigned int lineNum, std::string msg) + : ghoul::RuntimeError( + fmt::format("Error @ line {}: {}", lineNum, std::move(msg)), + "profileFile" + ) + {} + }; Profile() = default; Profile(const std::vector& content); diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index e0e1766d3a..6ce39e8d81 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -54,19 +54,6 @@ namespace { template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; - struct ProfileParsingError : public ghoul::RuntimeError { - explicit ProfileParsingError(std::string msg) - : ghoul::RuntimeError(std::move(msg), "profileFile") - {} - - ProfileParsingError(unsigned int lineNum, std::string msg) - : ghoul::RuntimeError( - fmt::format("Error @ line {}: {}", lineNum, std::move(msg)), - "profileFile" - ) - {} - }; - std::vector changedProperties( const properties::PropertyOwner& po) { @@ -111,7 +98,7 @@ namespace { if (line == headerMarkNodes) { return Section::MarkNodes; } if (line == headerAdditionalScripts) { return Section::AdditionalScripts; } - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Invalid section header: {}", line) ); @@ -121,7 +108,7 @@ namespace { { std::vector parts = ghoul::tokenizeString(line, '.'); if (parts.size() > 2) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 1-2 version components, got {}", parts.size()) ); @@ -141,7 +128,7 @@ namespace { return version; } catch (const std::invalid_argument&) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, "Error parsing Version. Version number is not a number" ); @@ -151,7 +138,7 @@ namespace { [[ nodiscard ]] Profile::Module parseModule(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) ); @@ -178,7 +165,7 @@ namespace { { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() < 2) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 2 fields in a Meta line, got {}", fields.size()) ); @@ -210,7 +197,7 @@ namespace { return { MetaLineType::License, content }; } else { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Unknown meta line type '{}'", type) ); @@ -220,7 +207,7 @@ namespace { [[ nodiscard ]] Profile::Asset parseAsset(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 2) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 2 fields in an Asset entry, got {}", fields.size()) ); @@ -235,7 +222,7 @@ namespace { [[ nodiscard ]] Profile::Property parseProperty(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) ); @@ -248,7 +235,7 @@ namespace { if (type == "setPropertyValueSingle") { return Profile::Property::SetType::SetPropertyValueSingle; } - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format( "Expected property set type 'setPropertyValue' or " @@ -265,7 +252,7 @@ namespace { [[ nodiscard ]] Profile::Keybinding parseKeybinding(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 6) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) ); @@ -275,7 +262,7 @@ namespace { kb.key = stringToKey(fields[0]); } catch (const ghoul::RuntimeError& e) { - throw ProfileParsingError(lineNumber, e.what()); + throw Profile::ParsingError(lineNumber, e.what()); } kb.documentation = fields[1]; kb.name = fields[2]; @@ -287,7 +274,7 @@ namespace { if (local == "true") { return true; } - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 'false' or 'true' for the local path, got {}", local) ); @@ -299,7 +286,7 @@ namespace { [[ nodiscard ]] Profile::Time parseTime(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 2) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) ); @@ -312,7 +299,7 @@ namespace { if (type == "relative") { return Profile::Time::Type::Relative; } - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected 'absolute' or 'relative' for the type, got {}", type) ); @@ -326,7 +313,7 @@ namespace { return std::stod(line); } catch (const std::invalid_argument&) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format("Expected a number for delta time entry, got '{}'", line) ); @@ -340,7 +327,7 @@ namespace { { if (type == Profile::CameraNavState::Type) { if (fields.size() != 8) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format( "Expected 8 fields in the Camera entry, got {}", fields.size() @@ -355,7 +342,7 @@ namespace { std::vector position = ghoul::tokenizeString(fields[4], ' '); if (position.size() != 3) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format( "Expected 3 fields for the camera's position, got {}", @@ -371,7 +358,7 @@ namespace { ); } catch (const std::invalid_argument&) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, "Camera's position components must be numbers" ); @@ -379,7 +366,7 @@ namespace { std::vector up = ghoul::tokenizeString(fields[5], ' '); if (up.size() != 0 && up.size() != 3) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format( "Expected 0 or 3 fields for the camera's up vector, got {}", @@ -396,7 +383,7 @@ namespace { ); } catch (const std::invalid_argument&) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, "Camera's up vector components must be numbers" ); @@ -408,7 +395,7 @@ namespace { camera.yaw = std::stod(fields[6]); } catch (const std::invalid_argument&) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, "Camera's yaw value must be a number" ); @@ -420,7 +407,7 @@ namespace { camera.pitch = std::stod(fields[7]); } catch (const std::invalid_argument&) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, "Camera's pitch value must be a number" ); @@ -430,7 +417,7 @@ namespace { } if (type == Profile::CameraGoToGeo::Type) { if (fields.size() != 5) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format( "Expected 5 fields in the Camera entry, got {}", fields.size() @@ -447,7 +434,7 @@ namespace { } return camera; } - throw ProfileParsingError( + throw Profile::ParsingError( lineNumber, fmt::format( "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", @@ -764,7 +751,7 @@ Profile::Profile(const std::vector& content) { } if (currentSection != Section::None && line[0] == '#') { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Sections in profile must be separated by empty lines" ); @@ -775,7 +762,7 @@ Profile::Profile(const std::vector& content) { currentSection = parseSection(line, lineNum); if (!foundVersion && currentSection != Section::Version) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, fmt::format( "First header in the file must be Version, but got {}", line @@ -784,7 +771,7 @@ Profile::Profile(const std::vector& content) { } if (currentSection == Section::Meta && foundMeta) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta section can only appear once per profile" ); @@ -792,7 +779,7 @@ Profile::Profile(const std::vector& content) { break; case Section::Version: if (foundVersion) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Version section can only appear once per profile" ); @@ -811,7 +798,7 @@ Profile::Profile(const std::vector& content) { switch (m.first) { case MetaLineType::Name: if (!_meta->name.empty()) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta information 'Name' specified twice" ); @@ -820,7 +807,7 @@ Profile::Profile(const std::vector& content) { break; case MetaLineType::Version: if (!_meta->version.empty()) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta information 'Version' specified twice" ); @@ -829,7 +816,7 @@ Profile::Profile(const std::vector& content) { break; case MetaLineType::Description: if (!_meta->description.empty()) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta information 'Description' specified twice" ); @@ -838,7 +825,7 @@ Profile::Profile(const std::vector& content) { break; case MetaLineType::Author: if (!_meta->author.empty()) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta information 'Author' specified twice" ); @@ -847,7 +834,7 @@ Profile::Profile(const std::vector& content) { break; case MetaLineType::URL: if (!_meta->url.empty()) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta information 'URL' specified twice" ); @@ -856,7 +843,7 @@ Profile::Profile(const std::vector& content) { break; case MetaLineType::License: if (!_meta->license.empty()) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Meta information 'License' specified twice" ); @@ -895,7 +882,7 @@ Profile::Profile(const std::vector& content) { } case Section::Time: if (foundTime) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Time section can only appear once per profile" ); @@ -912,7 +899,7 @@ Profile::Profile(const std::vector& content) { } case Section::Camera: if (foundCamera) { - throw ProfileParsingError( + throw Profile::ParsingError( lineNum, "Camera section can only appear once per profile" );