From 6784a5dcb3dc99c3a5b9cf1b257ecc9ba507aa4e Mon Sep 17 00:00:00 2001 From: Alfred Reynolds Date: Thu, 12 Aug 2021 16:12:13 +1200 Subject: [PATCH] - Move the folder/app configuration logic into its own file --- README.md | 10 ++- src/appconfig.cpp | 181 +++++++++++++++++++++++++++++++++++++++++ src/appconfig.h | 52 ++++++++++++ src/main.cpp | 183 +++--------------------------------------- src/pathtraverser.cpp | 45 +++-------- 5 files changed, 260 insertions(+), 211 deletions(-) create mode 100644 src/appconfig.cpp create mode 100644 src/appconfig.h diff --git a/README.md b/README.md index 3a6178f..19e2a6b 100644 --- a/README.md +++ b/README.md @@ -83,13 +83,17 @@ Supported keys and values in the JSON configuration are: * `debug` : set to true to enable verbose output from the program ## Folder Options file -When using the default or recursive folder mode we support having per folder display options. The options are stored in a file called "options.json" and currently support the following option +When using the default or recursive folder mode we support having per folder display options. The options are stored in a file called "options.json" in the images folder and support a subset of the applications configuration settings: ``` { - "fitAspectAxisToWindow": false + "stretch": false, + "aspect" : "m", + "rotationSeconds" : 300, + "opacity" : 200, + "blur" : 20 } ``` -* `fitAspectAxisToWindow` : apply the `--stretch` option to files in this folder +See the `Configuration File` section for details of each setting. ## Dependencies diff --git a/src/appconfig.cpp b/src/appconfig.cpp new file mode 100644 index 0000000..d27bf7f --- /dev/null +++ b/src/appconfig.cpp @@ -0,0 +1,181 @@ +#include "appconfig.h" + +#include +#include +#include +#include +#include +#include + +#include + +const std::string AppConfig::valid_aspects = "alpm"; // all, landscape, portait, monitor + +ImageAspect parseAspectFromString(char aspect) { + switch(aspect) + { + case 'l': + return ImageAspect_Landscape; + break; + case 'p': + return ImageAspect_Portrait; + break; + case 'm': + return ImageAspect_Monitor; + break; + default: + case 'a': + return ImageAspect_Any; + break; + } +} + +std::string ParseJSONString(QJsonObject jsonDoc, const char *key) { + if(jsonDoc.contains(key) && jsonDoc[key].isString()) + { + return jsonDoc[key].toString().toStdString(); + } + return ""; +} + +void SetJSONBool(bool &value, QJsonObject jsonDoc, const char *key) { + if(jsonDoc.contains(key) && jsonDoc[key].isBool()) + { + value = jsonDoc[key].toBool(); + } +} + +Config loadConfiguration(const std::string &configFilePath, const Config ¤tConfig, bool debugMode) { + QString jsonFile(configFilePath.c_str()); + QDir directory; + if(!directory.exists(jsonFile)) + { + return currentConfig; // nothing to load + } + + Config userConfig = currentConfig; + + if(debugMode) + { + std::cout << "Found options file: " << jsonFile.toStdString() << std::endl; + } + + QString val; + QFile file; + file.setFileName(jsonFile); + file.open(QIODevice::ReadOnly | QIODevice::Text); + val = file.readAll(); + file.close(); + QJsonDocument d = QJsonDocument::fromJson(val.toUtf8()); + QJsonObject jsonDoc = d.object(); + SetJSONBool(userConfig.baseDisplayOptions.fitAspectAxisToWindow, jsonDoc, "stretch"); + + std::string aspectString = ParseJSONString(jsonDoc, "aspect"); + if(!aspectString.empty()) + { + userConfig.baseDisplayOptions.onlyAspect = parseAspectFromString(aspectString[0]); + } + if(jsonDoc.contains("rotationSeconds") && jsonDoc["rotationSeconds"].isDouble()) + { + userConfig.rotationSeconds = (int)jsonDoc["rotationSeconds"].toDouble(); + } + + if(jsonDoc.contains("opacity") && jsonDoc["opacity"].isDouble()) + { + userConfig.backgroundOpacity = (int)jsonDoc["opacity"].toDouble(); + } + + if(jsonDoc.contains("blur") && jsonDoc["blur"].isDouble()) + { + userConfig.blurRadius = (int)jsonDoc["blur"].toDouble(); + } + + userConfig.loadTime = QDateTime::currentDateTime(); + return userConfig; +} + + +QString getAppConfigFilePath(const std::string &configPath) { + std::string userConfigFolder = "~/.config/slide/"; + std::string systemConfigFolder = "/etc/slide"; + QString baseConfigFilename("slide.options.json"); + + QDir directory(userConfigFolder.c_str()); + QString jsonFile = ""; + if (!configPath.empty()) + { + directory.setPath(configPath.c_str()); + jsonFile = directory.filePath(baseConfigFilename); + } + if(!directory.exists(jsonFile)) + { + directory.setPath(userConfigFolder.c_str()); + jsonFile = directory.filePath(baseConfigFilename); + } + if(!directory.exists(jsonFile)) + { + directory.setPath(systemConfigFolder.c_str()); + jsonFile = directory.filePath(baseConfigFilename); + } + + if(directory.exists(jsonFile)) + { + return jsonFile; + } + + return ""; +} + +AppConfig loadAppConfiguration(const AppConfig &commandLineConfig) { + QString jsonFile = getAppConfigFilePath(commandLineConfig.configPath); + QDir directory; + if(!directory.exists(jsonFile)) + { + return commandLineConfig; + } + + AppConfig loadedConfig = loadConfiguration(jsonFile.toStdString(), commandLineConfig, commandLineConfig.debugMode); + + QString val; + QFile file; + file.setFileName(jsonFile); + file.open(QIODevice::ReadOnly | QIODevice::Text); + val = file.readAll(); + file.close(); + QJsonDocument d = QJsonDocument::fromJson(val.toUtf8()); + QJsonObject jsonDoc = d.object(); + + SetJSONBool(loadedConfig.recursive, jsonDoc, "recursive"); + SetJSONBool(loadedConfig.shuffle, jsonDoc, "shuffle"); + SetJSONBool(loadedConfig.sorted, jsonDoc, "sorted"); + SetJSONBool(loadedConfig.debugMode, jsonDoc, "debug"); + + std::string overlayString = ParseJSONString(jsonDoc, "overlay"); + if(!overlayString.empty()) + { + loadedConfig.overlay = overlayString; + } + std::string pathString = ParseJSONString(jsonDoc, "path"); + if(!pathString.empty()) + { + loadedConfig.path = pathString; + } + std::string imageListString = ParseJSONString(jsonDoc, "imageList"); + if(!imageListString.empty()) + { + loadedConfig.imageList = imageListString; + } + + loadedConfig.configPath = commandLineConfig.configPath; + return loadedConfig; +} + +Config getConfigurationForFolder(const std::string &folderPath, const Config ¤tConfig, bool debugMode) { + QDir directory(folderPath.c_str()); + QString jsonFile = directory.filePath(QString("options.json")); + if(directory.exists(jsonFile)) + { + return loadConfiguration(jsonFile.toStdString(), currentConfig, debugMode ); + } + return currentConfig; +} \ No newline at end of file diff --git a/src/appconfig.h b/src/appconfig.h new file mode 100644 index 0000000..0b4398f --- /dev/null +++ b/src/appconfig.h @@ -0,0 +1,52 @@ + +#ifndef APPCONFIG_H +#define APPCONFIG_H +#include +#include "imagestructs.h" + +// configuration options that apply to an image/folder of images +struct Config { + public: + unsigned int rotationSeconds = 30; + int blurRadius = -1; + int backgroundOpacity = -1; + ImageDisplayOptions baseDisplayOptions; + QDateTime loadTime; +}; + +// app level configuration +struct AppConfig : public Config +{ + AppConfig() {} + AppConfig( const Config &inConfig ) : Config(inConfig) {} + std::string path = ""; + std::string configPath = ""; + + std::string overlay = ""; + std::string imageList = ""; // comma delimited list of images to show + + bool recursive = false; + bool shuffle = false; + bool sorted = false; + bool debugMode = false; + static const std::string valid_aspects; + + public: + bool PathOptionsChanged(AppConfig &other) { + if ( other.recursive != recursive || other.shuffle != shuffle + || other.sorted != sorted) + return true; + if ( other.path != path || other.imageList != imageList ) + return true; + return false; + } +}; + + +AppConfig loadAppConfiguration(const AppConfig &commandLineConfig); +Config getConfigurationForFolder(const std::string &folderPath, const Config ¤tConfig, bool debugMode); + +ImageAspect parseAspectFromString(char aspect); +QString getAppConfigFilePath(const std::string &configPath); + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 926243a..967e3e7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,12 +3,9 @@ #include "imageswitcher.h" #include "pathtraverser.h" #include "overlay.h" +#include "appconfig.h" + #include -#include -#include -#include -#include -#include #include #include #include @@ -23,165 +20,7 @@ void usage(std::string programName) { std::cerr << "Usage: " << programName << " [-t rotation_seconds] [-a aspect('l','p','a', 'm')] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder [-r] [-s] [-v] [--verbose] [--stretch] [-c config_file_path]" << std::endl; } -struct Config { - public: - std::string path = ""; - std::string configPath = ""; - unsigned int rotationSeconds = 30; - int blurRadius = -1; - int backgroundOpacity = -1; - bool recursive = false; - bool shuffle = false; - bool sorted = false; - bool debugMode = false; - ImageDisplayOptions baseDisplayOptions; - static const std::string valid_aspects; - std::string overlay = ""; - std::string imageList = ""; // comma delimited list of images to show - QDateTime loadTime; - public: - bool PathOptionsChanged(Config &other) { - if ( other.recursive != recursive || other.shuffle != shuffle - || other.sorted != sorted) - return true; - if ( other.path != path || other.imageList != imageList ) - return true; - return false; - } -}; - -const std::string Config::valid_aspects = "alpm"; // all, landscape, portait, monitor - -ImageAspect parseAspectFromString(char aspect) { - switch(aspect) - { - case 'l': - return ImageAspect_Landscape; - break; - case 'p': - return ImageAspect_Portrait; - break; - case 'm': - return ImageAspect_Monitor; - break; - default: - case 'a': - return ImageAspect_Any; - break; - } -} - -std::string ParseJSONString(QJsonObject jsonDoc, const char *key) { - if(jsonDoc.contains(key) && jsonDoc[key].isString()) - { - return jsonDoc[key].toString().toStdString(); - } - return ""; -} - -void SetJSONBool(bool &value, QJsonObject jsonDoc, const char *key) { - if(jsonDoc.contains(key) && jsonDoc[key].isBool()) - { - value = jsonDoc[key].toBool(); - } -} - -QString getConfigFilePath(const std::string &configPath) { - std::string userConfigFolder = "~/.config/slide/"; - std::string systemConfigFolder = "/etc/slide"; - QString baseConfigFilename("slide.options.json"); - - QDir directory(userConfigFolder.c_str()); - QString jsonFile = ""; - if (!configPath.empty()) - { - directory.setPath(configPath.c_str()); - jsonFile = directory.filePath(baseConfigFilename); - } - if(!directory.exists(jsonFile)) - { - directory.setPath(userConfigFolder.c_str()); - jsonFile = directory.filePath(baseConfigFilename); - } - if(!directory.exists(jsonFile)) - { - directory.setPath(systemConfigFolder.c_str()); - jsonFile = directory.filePath(baseConfigFilename); - } - - if(directory.exists(jsonFile)) - { - return jsonFile; - } - - return ""; -} - -Config loadConfiguration(const Config &commandLineConfig) { - QString jsonFile = getConfigFilePath(commandLineConfig.configPath); - QDir directory; - if(!directory.exists(jsonFile)) - { - return commandLineConfig; // nothing to load - } - - Config userConfig = commandLineConfig; - - if(userConfig.debugMode) - { - std::cout << "Found options file: " << jsonFile.toStdString() << std::endl; - } - - QString val; - QFile file; - file.setFileName(jsonFile); - file.open(QIODevice::ReadOnly | QIODevice::Text); - val = file.readAll(); - file.close(); - QJsonDocument d = QJsonDocument::fromJson(val.toUtf8()); - QJsonObject jsonDoc = d.object(); - SetJSONBool(userConfig.baseDisplayOptions.fitAspectAxisToWindow, jsonDoc, "stretch"); - SetJSONBool(userConfig.recursive, jsonDoc, "recursive"); - SetJSONBool(userConfig.shuffle, jsonDoc, "shuffle"); - SetJSONBool(userConfig.sorted, jsonDoc, "sorted"); - SetJSONBool(userConfig.debugMode, jsonDoc, "debug"); - - std::string aspectString = ParseJSONString(jsonDoc, "aspect"); - if(!aspectString.empty()) - { - userConfig.baseDisplayOptions.onlyAspect = parseAspectFromString(aspectString[0]); - } - if(jsonDoc.contains("rotationSeconds") && jsonDoc["rotationSeconds"].isDouble()) - { - userConfig.rotationSeconds = (int)jsonDoc["rotationSeconds"].toDouble(); - } - - if(jsonDoc.contains("opacity") && jsonDoc["opacity"].isDouble()) - { - userConfig.backgroundOpacity = (int)jsonDoc["opacity"].toDouble(); - } - - if(jsonDoc.contains("blur") && jsonDoc["blur"].isDouble()) - { - userConfig.blurRadius = (int)jsonDoc["blur"].toDouble(); - } - - std::string overlayString = ParseJSONString(jsonDoc, "overlay"); - if(!overlayString.empty()) - { - userConfig.overlay = overlayString; - } - std::string pathString = ParseJSONString(jsonDoc, "path"); - if(!pathString.empty()) - { - userConfig.path = pathString; - } - - userConfig.loadTime = QDateTime::currentDateTime(); - return userConfig; -} - -bool parseCommandLine(Config &appConfig, int argc, char *argv[]) { +bool parseCommandLine(AppConfig &appConfig, int argc, char *argv[]) { int opt; int debugInt = 0; int stretchInt = 0; @@ -261,7 +100,7 @@ bool parseCommandLine(Config &appConfig, int argc, char *argv[]) { return true; } -void ConfigureWindowFromSettings(MainWindow &w, const Config &appConfig) +void ConfigureWindowFromSettings(MainWindow &w, const AppConfig &appConfig) { if (appConfig.blurRadius>= 0) { @@ -279,7 +118,7 @@ void ConfigureWindowFromSettings(MainWindow &w, const Config &appConfig) w.setBaseOptions(appConfig.baseDisplayOptions); } -std::unique_ptr GetSelectorForConfig(const Config &appConfig) +std::unique_ptr GetSelectorForConfig(const AppConfig&appConfig) { std::unique_ptr pathTraverser; if (!appConfig.imageList.empty()) @@ -312,9 +151,9 @@ std::unique_ptr GetSelectorForConfig(const Config &appConfig) return selector; } -void ReloadConfigIfNeeded(Config &appConfig, MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector) +void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector) { - QString jsonFile = getConfigFilePath(appConfig.configPath); + QString jsonFile = getAppConfigFilePath(appConfig.configPath); QDir directory; if(!directory.exists(jsonFile)) { @@ -326,8 +165,8 @@ void ReloadConfigIfNeeded(Config &appConfig, MainWindow &w, ImageSwitcher *switc const std::string oldPath = appConfig.path; const std::string oldImageList = appConfig.imageList; - Config oldConfig = appConfig; - appConfig = loadConfiguration(appConfig); + AppConfig oldConfig = appConfig; + appConfig = loadAppConfiguration(appConfig); ConfigureWindowFromSettings(w, appConfig); if(appConfig.PathOptionsChanged(oldConfig)) @@ -345,14 +184,14 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); - Config commandLineAppConfig; + AppConfig commandLineAppConfig; if (!parseCommandLine(commandLineAppConfig, argc, argv)) { usage(argv[0]); return 1; } - Config appConfig = loadConfiguration(commandLineAppConfig); + AppConfig appConfig = loadAppConfiguration(commandLineAppConfig); if (appConfig.path.empty() && appConfig.imageList.empty()) { diff --git a/src/pathtraverser.cpp b/src/pathtraverser.cpp index db2ab73..d42385f 100644 --- a/src/pathtraverser.cpp +++ b/src/pathtraverser.cpp @@ -1,16 +1,13 @@ #include "pathtraverser.h" #include "mainwindow.h" +#include "appconfig.h" + #include -#include -#include #include #include -#include -#include -#include #include #include /* srand, rand */ -#define UNUSED(x) (void)(x) + PathTraverser::PathTraverser(const std::string path, bool debugModeIn): path(path), debugMode(debugModeIn) @@ -27,33 +24,9 @@ QStringList PathTraverser::getImageFormats() const { ImageDisplayOptions PathTraverser::LoadOptionsForDirectory(const std::string &directoryPath, const ImageDisplayOptions &baseOptions) const { - ImageDisplayOptions options = baseOptions; - QDir directory(directoryPath.c_str()); - QString jsonFile = directory.filePath(QString("options.json")); - if(directory.exists(jsonFile)) - { - if(debugMode) - { - std::cout << "Found options file" << std::endl; - } - QString val; - QFile file; - file.setFileName(jsonFile); - file.open(QIODevice::ReadOnly | QIODevice::Text); - val = file.readAll(); - file.close(); - QJsonDocument d = QJsonDocument::fromJson(val.toUtf8()); - QJsonObject jsonDoc = d.object(); - if(jsonDoc.contains("fitAspectAxisToWindow") && jsonDoc["fitAspectAxisToWindow"].isBool()) - { - options.fitAspectAxisToWindow = jsonDoc["fitAspectAxisToWindow"].toBool(); - if(debugMode) - { - std::cout << "Fit Aspect:" << options.fitAspectAxisToWindow << std::endl; - } - } - } - return options; + Config baseConfig; + baseConfig.baseDisplayOptions = baseOptions; + return getConfigurationForFolder(directoryPath, baseConfig, debugMode).baseDisplayOptions; } RecursivePathTraverser::RecursivePathTraverser(const std::string path,bool debugMode): @@ -106,7 +79,7 @@ const std::string DefaultPathTraverser::getImagePath(const std::string image) co ImageDisplayOptions DefaultPathTraverser::UpdateOptionsForImage(const std::string& filename, const ImageDisplayOptions& baseOptions) const { - UNUSED(filename); + Q_UNUSED(filename); return LoadOptionsForDirectory(directory.absolutePath().toStdString(), baseOptions); } @@ -133,7 +106,7 @@ const std::string ImageListPathTraverser::getImagePath(const std::string image) ImageDisplayOptions ImageListPathTraverser::UpdateOptionsForImage(const std::string& filename, const ImageDisplayOptions& baseOptions) const { // no per file options modification supported - UNUSED(filename); - UNUSED(baseOptions); + Q_UNUSED(filename); + Q_UNUSED(baseOptions); return ImageDisplayOptions(); }