From 3ef990acb99b954beda6614815022b7f017c2b4b Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Wed, 24 Jan 2018 17:55:24 +0100 Subject: Configuration class rework - Moved setValue to the header - Code readability - Removed secondary defaultCfg --- data/poi.cfg | 5 +- lib/settings/configuration.cpp | 177 +++------------------------------------- lib/settings/configuration.h | 97 ++++++++++++++-------- lib/settings/settingsdialog.cpp | 7 -- src/main.cpp | 89 ++++---------------- 5 files changed, 93 insertions(+), 282 deletions(-) diff --git a/data/poi.cfg b/data/poi.cfg index 2cf50d6..f6b2d2c 100644 --- a/data/poi.cfg +++ b/data/poi.cfg @@ -4,9 +4,6 @@ // Browser default settings browser = { - // true to generate user settings when run - firstRun = true; - // default profile name the browser should use; "" is off-the-record profile = ""; @@ -62,7 +59,7 @@ plugins = { // Profile settings profile = { - path = "~/.config/smolbote/Profiles"; + path = "~/.config/smolbote/profiles.d"; search = "https://duckduckgo.com/?q=$term&ia=web" homepage = "about:blank"; newtab = "about:blank"; diff --git a/lib/settings/configuration.cpp b/lib/settings/configuration.cpp index 64e8b38..10c284c 100644 --- a/lib/settings/configuration.cpp +++ b/lib/settings/configuration.cpp @@ -8,6 +8,7 @@ #include "configuration.h" #include +#include #include using namespace libconfig; @@ -16,40 +17,36 @@ Configuration::Configuration(const std::string &path, const std::string &home) { m_userCfg = new Config(); // prettier output - m_userCfg->setOptions(Config::OptionSemicolonSeparators | Config::OptionOpenBraceOnSeparateLine); + m_userCfg->setOption(Config::OptionSemicolonSeparators, true); + m_userCfg->setOption(Config::OptionColonAssignmentForGroups, false); + m_userCfg->setOption(Config::OptionColonAssignmentForNonGroups, false); + m_userCfg->setOption(Config::OptionOpenBraceOnSeparateLine, false); m_userCfg->setOption(Config::OptionFsync, true); m_userCfgPath = path; m_homePath = home; - - m_defaultCfg = new Config(); } Configuration::~Configuration() { delete m_userCfg; - delete m_defaultCfg; } -bool Configuration::read() +bool Configuration::read(const QString &path) { - try { - m_userCfg->readFile(m_userCfgPath.c_str()); - } catch(const FileIOException &e) { - return false; - } catch(const ParseException &e) { + QFile conf(path); + + if(!conf.open(QIODevice::ReadOnly)) { return false; } - return true; -} -bool Configuration::parse(const std::string &contents) -{ try { - m_userCfg->readString(contents); + m_userCfg->readString(conf.readAll().toStdString()); + conf.close(); } catch(const ParseException &e) { return false; } + return true; } @@ -71,16 +68,6 @@ bool Configuration::writeIfNeeded(const std::string &path) return true; } -bool Configuration::parseDefaultConfiguration(const std::string &contents) -{ - try { - m_defaultCfg->readString(contents); - } catch(const ParseException &e) { - return false; - } - return true; -} - std::vector Configuration::childrenSettings(const char *name) { std::vector groupNames; @@ -110,77 +97,6 @@ std::vector Configuration::childrenGroups(const char *name) return groupNames; } -void Configuration::resetValue(const char *path) -{ - if(!m_userCfg->exists(path) && m_defaultCfg->exists(path)) { - // entry doesn't exist, create path to it - // split path into array of items, sep=. - std::string s(path); - std::vector pathTokens; - std::string::size_type prev_pos = 0, pos = 0; - while((pos = s.find('.', pos)) != std::string::npos) { - std::string substring(s.substr(prev_pos, pos - prev_pos)); - pathTokens.push_back(substring); - prev_pos = ++pos; - } - pathTokens.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word - - s.clear(); - // iterate through items, creating the path along the way - for(const std::string &t : pathTokens) { - Setting &v = m_userCfg->lookup(s); - Setting &d = m_defaultCfg->lookup(s).lookup(t); - - if(!v.exists(t)) { - v.add(t, d.getType()); - } - - if(s.empty()) - s.append(t); - else - s.append('.' + t); - } - } - - // if the path doesn't exist in the defaultCfg, this will crash - - // entry exists, reset it - Setting &v = m_userCfg->lookup(path); - switch(v.getType()) { - case Setting::TypeNone: - break; - case Setting::TypeInt: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeInt64: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeFloat: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeString: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeBoolean: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeGroup: - break; - case Setting::TypeArray: - break; - case Setting::TypeList: - break; - } - - // if it's a string, it may contain a path - if(v.getType() == Setting::TypeString) { - std::string val(static_cast(v)); - v = patchHome(val, m_homePath).c_str(); - } - - changed = true; -} - std::string Configuration::castToString(const libconfig::Setting &v) const { // cast depending on type @@ -216,75 +132,6 @@ std::string Configuration::castToString(const libconfig::Setting &v) const } } -template -bool Configuration::setValue(std::string path, const T &val) -{ - if(m_userCfg->exists(path)) { - Setting &setting = m_userCfg->lookup(path); - // compiler complained about operator= not taking unsinged ints, longs and long longs - if constexpr(std::is_unsigned_v && !std::is_same_v) { - setting = static_cast>(val); - } else if constexpr(std::is_same_v) { - switch(setting.getType()) { - case Setting::TypeNone: - break; - - case Setting::TypeInt: - case Setting::TypeInt64: - setting = std::stoi(static_cast(val)); - break; - - case Setting::TypeFloat: - setting = std::stod(static_cast(val)); - break; - - case Setting::TypeString: - setting = static_cast(val).c_str(); - break; - - case Setting::TypeBoolean: - if(static_cast(val) == "true") { - setting = true; - } else if(static_cast(val) == "false") { - setting = false; - } - break; - - case Setting::TypeGroup: - break; - case Setting::TypeArray: - break; - case Setting::TypeList: - break; - } - - } else { - setting = val; - } - - changed = true; - return true; - } - - // the entry doesn't exist - return false; -} - -template bool Configuration::setValue(std::string path, const int &val); -template bool Configuration::setValue(std::string path, const unsigned int &val); -template bool Configuration::setValue(std::string path, const long &val); -template bool Configuration::setValue(std::string path, const unsigned long &val); - -template bool Configuration::setValue(std::string path, const long long &val); -template bool Configuration::setValue(std::string path, const unsigned long long &val); - -template bool Configuration::setValue(std::string path, const float &val); -template bool Configuration::setValue(std::string path, const double &val); - -template bool Configuration::setValue(std::string path, const bool &val); - -template bool Configuration::setValue(std::string path, const std::string &val); - std::string patchHome(const std::string &path, const std::string &home) { std::string r = path; diff --git a/lib/settings/configuration.h b/lib/settings/configuration.h index db93760..82e0c58 100644 --- a/lib/settings/configuration.h +++ b/lib/settings/configuration.h @@ -13,6 +13,7 @@ #include #include #include +#include class Configuration { @@ -20,35 +21,86 @@ public: explicit Configuration(const std::string &path, const std::string &home); ~Configuration(); - bool read(); - bool parse(const std::string &contents); + bool read(const QString &path); bool writeIfNeeded(const std::string &path = std::string()); - bool parseDefaultConfiguration(const std::string &contents); - std::vector childrenSettings(const char *name = ""); std::vector childrenGroups(const char *name = ""); - void resetValue(const char *path); - template std::optional value(const char *path) const { // if setting doesn't exist, give back a nullopt if(!m_userCfg->exists(path)) { - const_cast(this)->resetValue(path); - return value(path); + return std::nullopt; } const libconfig::Setting &v = m_userCfg->lookup(path); - if constexpr(std::is_same_v) - return std::optional(castToString(v)); - else + if constexpr(std::is_same_v) { + std::string r = castToString(v); + + // check if it's a path + if(r.front() == '~') { + r.replace(0, 1, m_homePath); + } + + return std::optional(r); + } else return std::optional(static_cast(v)); } template - bool setValue(std::string path, const T &val); + bool setValue(std::string path, const T &val) + { + if(!m_userCfg->exists(path)) { + return false; + } + + libconfig::Setting &setting = m_userCfg->lookup(path); + // compiler complained about operator= not taking unsinged ints, longs and long longs + if constexpr(std::is_unsigned_v && !std::is_same_v) { + setting = static_cast>(val); + } else if constexpr(std::is_same_v) { + switch(setting.getType()) { + case libconfig::Setting::TypeNone: + break; + + case libconfig::Setting::TypeInt: + case libconfig::Setting::TypeInt64: + setting = std::stoi(static_cast(val)); + break; + + case libconfig::Setting::TypeFloat: + setting = std::stod(static_cast(val)); + break; + + case libconfig::Setting::TypeString: + setting = static_cast(val).c_str(); + break; + + case libconfig::Setting::TypeBoolean: + if(static_cast(val) == "true") { + setting = true; + } else if(static_cast(val) == "false") { + setting = false; + } + break; + + case libconfig::Setting::TypeGroup: + break; + case libconfig::Setting::TypeArray: + break; + case libconfig::Setting::TypeList: + break; + } + + } else { + setting = val; + } + + changed = true; + return true; + } private: std::string castToString(const libconfig::Setting &v) const; @@ -56,29 +108,10 @@ private: bool changed = false; std::string m_homePath; std::string m_userCfgPath; - libconfig::Config *m_userCfg, *m_defaultCfg; + libconfig::Config *m_userCfg; }; // replace ~ with home std::string patchHome(const std::string &path, const std::string &home); -// instantiate functions -// this needs to be done because the implementation is in the cpp file - -// Settings::setValue<> -extern template bool Configuration::setValue(std::string path, const int &val); -extern template bool Configuration::setValue(std::string path, const unsigned int &val); -extern template bool Configuration::setValue(std::string path, const long &val); -extern template bool Configuration::setValue(std::string path, const unsigned long &val); - -extern template bool Configuration::setValue(std::string path, const long long &val); -extern template bool Configuration::setValue(std::string path, const unsigned long long &val); - -extern template bool Configuration::setValue(std::string path, const float &val); -extern template bool Configuration::setValue(std::string path, const double &val); - -extern template bool Configuration::setValue(std::string path, const bool &val); - -extern template bool Configuration::setValue(std::string path, const std::string &val); - #endif // CONFIGURATION_H diff --git a/lib/settings/settingsdialog.cpp b/lib/settings/settingsdialog.cpp index 2cad476..36b7d2c 100644 --- a/lib/settings/settingsdialog.cpp +++ b/lib/settings/settingsdialog.cpp @@ -71,20 +71,13 @@ inline QHBoxLayout *createEntry(Configuration *config, const std::string &path, { QLineEdit *lineEdit = new QLineEdit(widget); lineEdit->setText(QString::fromStdString(config->value(path.c_str()).value())); - QToolButton *resetButton = new QToolButton(widget); - resetButton->setIcon(widget->style()->standardIcon(QStyle::SP_DialogResetButton)); - QObject::connect(resetButton, &QToolButton::clicked, widget, [config, path, lineEdit]() { - config->resetValue(path.c_str()); - lineEdit->setText(QString::fromStdString(config->value(path.c_str()).value())); - }); QObject::connect(lineEdit, &QLineEdit::editingFinished, widget, [config, path, lineEdit]() { config->setValue(path, lineEdit->text().toStdString()); }); QHBoxLayout *hBox = new QHBoxLayout(); hBox->addWidget(lineEdit); - hBox->addWidget(resetButton); return hBox; } diff --git a/src/main.cpp b/src/main.cpp index 9356820..66df526 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,31 +19,7 @@ #include #endif -// read config into std::string, supports qrc -inline std::string readConfig(const QString &path) -{ - QFile conf(path); - std::string ret; - if(conf.open(QIODevice::ReadOnly)) { - ret = conf.readAll().toStdString(); - conf.close(); - } - return ret; -} - -void bootstrapUserConfig(const std::string &path, Configuration &config) -{ - // set firstRun to false so we don't re-init on every run - config.setValue("browser.firstRun", false); - - config.resetValue("filter.path"); - config.resetValue("profile.path"); - config.resetValue("bookmarks.path"); - config.resetValue("downloads.path"); - config.resetValue("plugins.path"); -} - -int main(int argc, char *argv[]) +int main(int argc, char **argv) { // Create application object Browser instance(argc, argv); @@ -61,7 +37,16 @@ int main(int argc, char *argv[]) // user config, ~/.config/smolbote/smolbote.cfg or empty if there is none QCommandLineOption configOption({ "c", "config" }, "Set configuration file.", "path"); - configOption.setDefaultValue(QStandardPaths::locate(QStandardPaths::AppConfigLocation, "smolbote.cfg")); + { + // try to locate an existing config + QString path = QStandardPaths::locate(QStandardPaths::AppConfigLocation, "smolbote.cfg"); + + // it's possible there is no config, so set the path properly + if(path.isEmpty()) + path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/smolbote.cfg"; + + configOption.setDefaultValue(path); + } parser.addOption(configOption); // default config, :/poi.cfg @@ -69,14 +54,6 @@ int main(int argc, char *argv[]) defaultConfigOption.setDefaultValue(":/poi.cfg"); parser.addOption(defaultConfigOption); - // print default config, so users can easily create their overrides - QCommandLineOption printDefaultConfigOption("print-default-config", "Print default configuration."); - parser.addOption(printDefaultConfigOption); - - // generate user config - QCommandLineOption generateUserConfigOption("generate-user-config", "Generate user configuration and exit."); - parser.addOption(generateUserConfigOption); - QCommandLineOption profileOption({ "p", "profile" }, "Use this profile.", "PROFILE"); profileOption.setDefaultValue(""); parser.addOption(profileOption); @@ -99,50 +76,14 @@ int main(int argc, char *argv[]) qDebug("profile=%s", qUtf8Printable(parser.value(profileOption))); #endif - if(parser.isSet(printDefaultConfigOption)) { - std::cout << readConfig(parser.value(defaultConfigOption)); - std::cout.flush(); - return 0; - } - std::shared_ptr config = std::make_shared( parser.value(configOption).toStdString(), QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString()); - config->read(); - config->parseDefaultConfiguration(readConfig(parser.value(defaultConfigOption))); - - // check if first run - if(config->value("browser.firstRun").value_or(true) || parser.isSet(generateUserConfigOption)) { - // create a user config file - QString path = parser.value(configOption); - // make sure we have a path - if(path.isEmpty()) { - path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/smolbote.cfg"; - } - // make sure the directory exists - QDir configDir = QFileInfo(path).absoluteDir(); - if(!configDir.exists()) { - configDir.mkpath("."); - } - - // remove any existing config - if(QFile::exists(path)) { - QFile::remove(path); - } - - config->parse(readConfig(parser.value(defaultConfigOption))); - - // patch paths - bootstrapUserConfig(path.toStdString(), *config); - - std::cout << "Writing configuration: " << (config->writeIfNeeded(path.toStdString()) ? "ok" : "failed") << std::endl; - - // exit if this is the only thing we needed to do - if(parser.isSet(generateUserConfigOption)) { - return 0; - } - } + // first load the default configuration + config->read(parser.value(defaultConfigOption)); + // then load in the user configuration, which will overwrite it + config->read(parser.value(configOption)); // check for other instances // if we socket hasn't been disabled (socket is not none) -- cgit v1.2.1