- Move the folder/app configuration logic into its own file

This commit is contained in:
Alfred Reynolds
2021-08-12 16:12:13 +12:00
parent 9a5b78cbfd
commit 6784a5dcb3
5 changed files with 260 additions and 211 deletions

View File

@@ -83,13 +83,17 @@ Supported keys and values in the JSON configuration are:
* `debug` : set to true to enable verbose output from the program * `debug` : set to true to enable verbose output from the program
## Folder Options file ## 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 ## Dependencies

181
src/appconfig.cpp Normal file
View File

@@ -0,0 +1,181 @@
#include "appconfig.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QDateTime>
#include <QFileInfo>
#include <QDir>
#include <iostream>
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 &currentConfig, 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 &currentConfig, 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;
}

52
src/appconfig.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef APPCONFIG_H
#define APPCONFIG_H
#include <QDateTime>
#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 &currentConfig, bool debugMode);
ImageAspect parseAspectFromString(char aspect);
QString getAppConfigFilePath(const std::string &configPath);
#endif

View File

@@ -3,12 +3,9 @@
#include "imageswitcher.h" #include "imageswitcher.h"
#include "pathtraverser.h" #include "pathtraverser.h"
#include "overlay.h" #include "overlay.h"
#include "appconfig.h"
#include <QApplication> #include <QApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QDateTime>
#include <QFileInfo>
#include <iostream> #include <iostream>
#include <sys/file.h> #include <sys/file.h>
#include <errno.h> #include <errno.h>
@@ -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; 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 { bool parseCommandLine(AppConfig &appConfig, int argc, char *argv[]) {
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[]) {
int opt; int opt;
int debugInt = 0; int debugInt = 0;
int stretchInt = 0; int stretchInt = 0;
@@ -261,7 +100,7 @@ bool parseCommandLine(Config &appConfig, int argc, char *argv[]) {
return true; return true;
} }
void ConfigureWindowFromSettings(MainWindow &w, const Config &appConfig) void ConfigureWindowFromSettings(MainWindow &w, const AppConfig &appConfig)
{ {
if (appConfig.blurRadius>= 0) if (appConfig.blurRadius>= 0)
{ {
@@ -279,7 +118,7 @@ void ConfigureWindowFromSettings(MainWindow &w, const Config &appConfig)
w.setBaseOptions(appConfig.baseDisplayOptions); w.setBaseOptions(appConfig.baseDisplayOptions);
} }
std::unique_ptr<ImageSelector> GetSelectorForConfig(const Config &appConfig) std::unique_ptr<ImageSelector> GetSelectorForConfig(const AppConfig&appConfig)
{ {
std::unique_ptr<PathTraverser> pathTraverser; std::unique_ptr<PathTraverser> pathTraverser;
if (!appConfig.imageList.empty()) if (!appConfig.imageList.empty())
@@ -312,9 +151,9 @@ std::unique_ptr<ImageSelector> GetSelectorForConfig(const Config &appConfig)
return selector; 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; QDir directory;
if(!directory.exists(jsonFile)) 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 oldPath = appConfig.path;
const std::string oldImageList = appConfig.imageList; const std::string oldImageList = appConfig.imageList;
Config oldConfig = appConfig; AppConfig oldConfig = appConfig;
appConfig = loadConfiguration(appConfig); appConfig = loadAppConfiguration(appConfig);
ConfigureWindowFromSettings(w, appConfig); ConfigureWindowFromSettings(w, appConfig);
if(appConfig.PathOptionsChanged(oldConfig)) if(appConfig.PathOptionsChanged(oldConfig))
@@ -345,14 +184,14 @@ int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
Config commandLineAppConfig; AppConfig commandLineAppConfig;
if (!parseCommandLine(commandLineAppConfig, argc, argv)) if (!parseCommandLine(commandLineAppConfig, argc, argv))
{ {
usage(argv[0]); usage(argv[0]);
return 1; return 1;
} }
Config appConfig = loadConfiguration(commandLineAppConfig); AppConfig appConfig = loadAppConfiguration(commandLineAppConfig);
if (appConfig.path.empty() && appConfig.imageList.empty()) if (appConfig.path.empty() && appConfig.imageList.empty())
{ {

View File

@@ -1,16 +1,13 @@
#include "pathtraverser.h" #include "pathtraverser.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "appconfig.h"
#include <QDirIterator> #include <QDirIterator>
#include <QTimer>
#include <QApplication>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <iostream> #include <iostream>
#include <stdlib.h> /* srand, rand */ #include <stdlib.h> /* srand, rand */
#define UNUSED(x) (void)(x)
PathTraverser::PathTraverser(const std::string path, bool debugModeIn): PathTraverser::PathTraverser(const std::string path, bool debugModeIn):
path(path), debugMode(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 PathTraverser::LoadOptionsForDirectory(const std::string &directoryPath, const ImageDisplayOptions &baseOptions) const
{ {
ImageDisplayOptions options = baseOptions; Config baseConfig;
QDir directory(directoryPath.c_str()); baseConfig.baseDisplayOptions = baseOptions;
QString jsonFile = directory.filePath(QString("options.json")); return getConfigurationForFolder(directoryPath, baseConfig, debugMode).baseDisplayOptions;
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;
} }
RecursivePathTraverser::RecursivePathTraverser(const std::string path,bool debugMode): 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 ImageDisplayOptions DefaultPathTraverser::UpdateOptionsForImage(const std::string& filename, const ImageDisplayOptions& baseOptions) const
{ {
UNUSED(filename); Q_UNUSED(filename);
return LoadOptionsForDirectory(directory.absolutePath().toStdString(), baseOptions); 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 ImageDisplayOptions ImageListPathTraverser::UpdateOptionsForImage(const std::string& filename, const ImageDisplayOptions& baseOptions) const
{ {
// no per file options modification supported // no per file options modification supported
UNUSED(filename); Q_UNUSED(filename);
UNUSED(baseOptions); Q_UNUSED(baseOptions);
return ImageDisplayOptions(); return ImageDisplayOptions();
} }