- Add a "scheduler" key to the config file that lets you define multiple image selectors and time windows they are valid for
This commit is contained in:
@@ -150,6 +150,67 @@ QString getAppConfigFilePath(const std::string &configPath) {
|
||||
return "";
|
||||
}
|
||||
|
||||
QVector<PathEntry> parsePathEntry(QJsonObject &jsonMainDoc, bool baseRecursive, bool baseShuffle, bool baseSorted)
|
||||
{
|
||||
QVector<PathEntry> pathEntries;
|
||||
|
||||
if(jsonMainDoc.contains("scheduler") && jsonMainDoc["scheduler"].isArray())
|
||||
{
|
||||
QJsonArray jsonArray = jsonMainDoc["scheduler"].toArray();
|
||||
foreach (const QJsonValue & value, jsonArray)
|
||||
{
|
||||
PathEntry entry;
|
||||
entry.recursive = baseRecursive;
|
||||
entry.sorted = baseSorted;
|
||||
entry.shuffle = baseShuffle;
|
||||
|
||||
QJsonObject schedulerJson = value.toObject();
|
||||
|
||||
SetJSONBool(entry.recursive, schedulerJson, "recursive");
|
||||
SetJSONBool(entry.shuffle, schedulerJson, "shuffle");
|
||||
SetJSONBool(entry.sorted, schedulerJson, "sorted");
|
||||
|
||||
std::string pathString = ParseJSONString(schedulerJson, "path");
|
||||
if(!pathString.empty()) {
|
||||
entry.path = pathString;
|
||||
}
|
||||
std::string imageListString = ParseJSONString(schedulerJson, "imageList");
|
||||
if(!imageListString.empty()) {
|
||||
entry.imageList = imageListString;
|
||||
}
|
||||
std::string typeString = ParseJSONString(schedulerJson, "type");
|
||||
if(!pathString.empty()) {
|
||||
entry.type = typeString;
|
||||
}
|
||||
SetJSONBool(entry.exclusive, schedulerJson, "exclusive");
|
||||
|
||||
if(schedulerJson.contains("times") && schedulerJson["times"].isArray())
|
||||
{
|
||||
QJsonArray jsonTimesArray = schedulerJson["times"].toArray();
|
||||
foreach (const QJsonValue & timesValue, jsonTimesArray)
|
||||
{
|
||||
QJsonObject timesJson = timesValue.toObject();
|
||||
if(timesJson.contains("start") || timesJson.contains("end"))
|
||||
{
|
||||
DisplayTimeWindow window;
|
||||
if(timesJson.contains("start"))
|
||||
{
|
||||
window.startDisplay = QTime::fromString(timesJson["start"].toString());
|
||||
}
|
||||
if(timesJson.contains("end"))
|
||||
{
|
||||
window.endDisplay = QTime::fromString(timesJson["end"].toString());
|
||||
}
|
||||
entry.timeWindows.append(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
pathEntries.append(entry);
|
||||
}
|
||||
}
|
||||
return pathEntries;
|
||||
}
|
||||
|
||||
AppConfig loadAppConfiguration(const AppConfig &commandLineConfig) {
|
||||
QString jsonFile = getAppConfigFilePath(commandLineConfig.configPath);
|
||||
QDir directory;
|
||||
@@ -169,9 +230,10 @@ AppConfig loadAppConfiguration(const AppConfig &commandLineConfig) {
|
||||
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");
|
||||
bool baseRecursive, baseShuffle, baseSorted;
|
||||
SetJSONBool(baseRecursive, jsonDoc, "recursive");
|
||||
SetJSONBool(baseShuffle, jsonDoc, "shuffle");
|
||||
SetJSONBool(baseSorted, jsonDoc, "sorted");
|
||||
SetJSONBool(loadedConfig.debugMode, jsonDoc, "debug");
|
||||
|
||||
std::string overlayString = ParseJSONString(jsonDoc, "overlay");
|
||||
@@ -179,17 +241,26 @@ AppConfig loadAppConfiguration(const AppConfig &commandLineConfig) {
|
||||
{
|
||||
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.paths = parsePathEntry(jsonDoc, baseRecursive, baseShuffle, baseSorted);
|
||||
if(loadedConfig.paths.count() <= 0)
|
||||
{
|
||||
PathEntry entry;
|
||||
entry.recursive = baseRecursive;
|
||||
entry.sorted = baseSorted;
|
||||
entry.shuffle = baseShuffle;
|
||||
std::string pathString = ParseJSONString(jsonDoc, "path");
|
||||
if(!pathString.empty())
|
||||
{
|
||||
entry.path = pathString;
|
||||
}
|
||||
std::string imageListString = ParseJSONString(jsonDoc, "imageList");
|
||||
if(!imageListString.empty())
|
||||
{
|
||||
entry.imageList = imageListString;
|
||||
}
|
||||
loadedConfig.paths.append(entry);
|
||||
}
|
||||
loadedConfig.configPath = commandLineConfig.configPath;
|
||||
return loadedConfig;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#define APPCONFIG_H
|
||||
#include <QDateTime>
|
||||
#include "imagestructs.h"
|
||||
#include <QVector>
|
||||
|
||||
// configuration options that apply to an image/folder of images
|
||||
struct Config {
|
||||
@@ -14,34 +15,44 @@ struct Config {
|
||||
QDateTime loadTime;
|
||||
};
|
||||
|
||||
// app level configuration
|
||||
struct AppConfig : public Config
|
||||
{
|
||||
AppConfig() {}
|
||||
AppConfig( const Config &inConfig ) : Config(inConfig) {}
|
||||
std::string path = "";
|
||||
std::string configPath = "";
|
||||
struct PathEntry {
|
||||
QVector<DisplayTimeWindow> timeWindows;
|
||||
std::string path = "";
|
||||
std::string imageList = "";
|
||||
std::string type = "";
|
||||
bool exclusive = false;
|
||||
|
||||
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;
|
||||
}
|
||||
bool recursive = false;
|
||||
bool shuffle = false;
|
||||
bool sorted = false;
|
||||
};
|
||||
|
||||
// app level configuration
|
||||
struct AppConfig : public Config {
|
||||
AppConfig() {}
|
||||
AppConfig( const Config &inConfig ) : Config(inConfig) {}
|
||||
std::string configPath = "";
|
||||
std::string overlay = "";
|
||||
QVector<PathEntry> paths;
|
||||
|
||||
bool debugMode = false;
|
||||
|
||||
static const std::string valid_aspects;
|
||||
public:
|
||||
bool PathOptionsChanged(AppConfig &other) {
|
||||
if (paths.count() != other.paths.count())
|
||||
return true;
|
||||
for(int index = 0; index < paths.count(); ++index)
|
||||
{
|
||||
if ( other.paths[index].recursive != paths[index].recursive || other.paths[index].shuffle != paths[index].shuffle
|
||||
|| other.paths[index].sorted != paths[index].sorted)
|
||||
return true;
|
||||
if ( other.paths[index].path != paths[index].path || other.paths[index].imageList != paths[index].imageList )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
AppConfig loadAppConfiguration(const AppConfig &commandLineConfig);
|
||||
Config getConfigurationForFolder(const std::string &folderPath, const Config ¤tConfig, bool debugMode);
|
||||
|
||||
@@ -17,6 +17,8 @@ ImageSelector::ImageSelector(std::unique_ptr<PathTraverser>& pathTraverserIn):
|
||||
{
|
||||
}
|
||||
|
||||
ImageSelector::ImageSelector() {}
|
||||
|
||||
ImageSelector::~ImageSelector(){}
|
||||
|
||||
void ImageSelector::setDebugMode(bool debugModeIn)
|
||||
@@ -134,7 +136,7 @@ bool ImageSelector::imageInsideTimeWindow(const QVector<DisplayTimeWindow> &time
|
||||
if(debugMode && timeWindows.count() > 0)
|
||||
{
|
||||
std::cout << "image display time outside windows: " << std::endl;
|
||||
for(auto timeWindow : timeWindows)
|
||||
for(auto &timeWindow : timeWindows)
|
||||
{
|
||||
std::cout << "time: " << timeWindow.startDisplay.toString().toStdString() << "-" << timeWindow.endDisplay.toString().toStdString() << std::endl;
|
||||
}
|
||||
@@ -324,3 +326,51 @@ void SortedImageSelector::reloadImagesIfEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ListImageSelector::ListImageSelector()
|
||||
{
|
||||
currentSelector = imageSelectors.begin();
|
||||
}
|
||||
|
||||
ListImageSelector::~ListImageSelector()
|
||||
{
|
||||
}
|
||||
|
||||
void ListImageSelector::AddImageSelector(std::unique_ptr<ImageSelector>& selector, const QVector<DisplayTimeWindow> &displayTimeWindows, const bool exclusiveIn)
|
||||
{
|
||||
SelectoryEntry entry;
|
||||
entry.selector = std::move(selector);
|
||||
entry.displayTimeWindows = displayTimeWindows;
|
||||
entry.exclusive = exclusiveIn;
|
||||
imageSelectors.push_back(std::move(entry));
|
||||
currentSelector = imageSelectors.begin();
|
||||
}
|
||||
|
||||
|
||||
const ImageDetails ListImageSelector::getNextImage(const ImageDisplayOptions& baseOptions)
|
||||
{
|
||||
// check for exclusive time windows
|
||||
for(auto& selector: imageSelectors)
|
||||
{
|
||||
if (imageInsideTimeWindow(selector.displayTimeWindows) && selector.exclusive)
|
||||
{
|
||||
return selector.selector->getNextImage(baseOptions);
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to the next in the list
|
||||
do
|
||||
{
|
||||
++currentSelector;
|
||||
if(currentSelector == imageSelectors.end())
|
||||
{
|
||||
currentSelector = imageSelectors.begin();
|
||||
}
|
||||
if (imageInsideTimeWindow(currentSelector->displayTimeWindows))
|
||||
{
|
||||
return currentSelector->selector->getNextImage(baseOptions);
|
||||
}
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include "imagestructs.h"
|
||||
|
||||
class MainWindow;
|
||||
@@ -13,6 +14,7 @@ class ImageSelector
|
||||
{
|
||||
public:
|
||||
ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
||||
ImageSelector(); // use case for when you don't own your own traverser
|
||||
virtual ~ImageSelector();
|
||||
virtual const ImageDetails getNextImage(const ImageDisplayOptions &baseOptions) = 0;
|
||||
void setDebugMode(bool debugModeIn);
|
||||
@@ -61,4 +63,22 @@ private:
|
||||
void reloadImagesIfEmpty();
|
||||
QStringList images;
|
||||
};
|
||||
|
||||
class ListImageSelector : public ImageSelector
|
||||
{
|
||||
public:
|
||||
ListImageSelector();
|
||||
virtual ~ListImageSelector();
|
||||
virtual const ImageDetails getNextImage(const ImageDisplayOptions &baseOptions);
|
||||
void AddImageSelector(std::unique_ptr<ImageSelector>& selector, const QVector<DisplayTimeWindow> &displayTimeWindows, const bool exclusiveIn);
|
||||
|
||||
private:
|
||||
struct SelectoryEntry {
|
||||
std::unique_ptr<ImageSelector> selector;
|
||||
QVector<DisplayTimeWindow> displayTimeWindows;
|
||||
bool exclusive = false;
|
||||
};
|
||||
std::vector<SelectoryEntry> imageSelectors;
|
||||
std::vector<SelectoryEntry>::iterator currentSelector;
|
||||
};
|
||||
#endif // IMAGESELECTOR_H
|
||||
|
||||
65
src/main.cpp
65
src/main.cpp
@@ -39,7 +39,9 @@ bool parseCommandLine(AppConfig &appConfig, int argc, char *argv[]) {
|
||||
return false;
|
||||
break;
|
||||
case 'p':
|
||||
appConfig.path = optarg;
|
||||
if(appConfig.paths.count() == 0)
|
||||
appConfig.paths.append(PathEntry());
|
||||
appConfig.paths[0].path = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
if (appConfig.valid_aspects.find(optarg[0]) == std::string::npos)
|
||||
@@ -62,14 +64,20 @@ bool parseCommandLine(AppConfig &appConfig, int argc, char *argv[]) {
|
||||
appConfig.backgroundOpacity = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
appConfig.recursive = true;
|
||||
if(appConfig.paths.count() == 0)
|
||||
appConfig.paths.append(PathEntry());
|
||||
appConfig.paths[0].recursive = true;
|
||||
break;
|
||||
case 's':
|
||||
appConfig.shuffle = true;
|
||||
if(appConfig.paths.count() == 0)
|
||||
appConfig.paths.append(PathEntry());
|
||||
appConfig.paths[0].shuffle = true;
|
||||
std::cout << "Shuffle mode is on." << std::endl;
|
||||
break;
|
||||
case 'S':
|
||||
appConfig.sorted = true;
|
||||
if(appConfig.paths.count() == 0)
|
||||
appConfig.paths.append(PathEntry());
|
||||
appConfig.paths[0].sorted = true;
|
||||
break;
|
||||
case 'O':
|
||||
appConfig.overlay = optarg;
|
||||
@@ -78,7 +86,9 @@ bool parseCommandLine(AppConfig &appConfig, int argc, char *argv[]) {
|
||||
appConfig.debugMode = true;
|
||||
break;
|
||||
case 'i':
|
||||
appConfig.imageList = optarg;
|
||||
if(appConfig.paths.count() == 0)
|
||||
appConfig.paths.append(PathEntry());
|
||||
appConfig.paths[0].imageList = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
appConfig.configPath = optarg;
|
||||
@@ -118,28 +128,28 @@ void ConfigureWindowFromSettings(MainWindow &w, const AppConfig &appConfig)
|
||||
w.setBaseOptions(appConfig.baseDisplayOptions);
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageSelector> GetSelectorForConfig(const AppConfig&appConfig)
|
||||
std::unique_ptr<ImageSelector> GetSelectorForConfig(const PathEntry& path, const bool debugMode)
|
||||
{
|
||||
std::unique_ptr<PathTraverser> pathTraverser;
|
||||
if (!appConfig.imageList.empty())
|
||||
if (!path.imageList.empty())
|
||||
{
|
||||
pathTraverser = std::unique_ptr<PathTraverser>(new ImageListPathTraverser(appConfig.imageList, appConfig.debugMode));
|
||||
pathTraverser = std::unique_ptr<PathTraverser>(new ImageListPathTraverser(path.imageList, debugMode));
|
||||
}
|
||||
else if (appConfig.recursive)
|
||||
else if (path.recursive)
|
||||
{
|
||||
pathTraverser = std::unique_ptr<PathTraverser>(new RecursivePathTraverser(appConfig.path, appConfig.debugMode));
|
||||
pathTraverser = std::unique_ptr<PathTraverser>(new RecursivePathTraverser(path.path, debugMode));
|
||||
}
|
||||
else
|
||||
{
|
||||
pathTraverser = std::unique_ptr<PathTraverser>(new DefaultPathTraverser(appConfig.path, appConfig.debugMode));
|
||||
pathTraverser = std::unique_ptr<PathTraverser>(new DefaultPathTraverser(path.path, debugMode));
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageSelector> selector;
|
||||
if (appConfig.sorted)
|
||||
if (path.sorted)
|
||||
{
|
||||
selector = std::unique_ptr<ImageSelector>(new SortedImageSelector(pathTraverser));
|
||||
}
|
||||
else if (appConfig.shuffle)
|
||||
else if (path.shuffle)
|
||||
{
|
||||
selector = std::unique_ptr<ImageSelector>(new ShuffleImageSelector(pathTraverser));
|
||||
}
|
||||
@@ -151,6 +161,26 @@ std::unique_ptr<ImageSelector> GetSelectorForConfig(const AppConfig&appConfig)
|
||||
return selector;
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageSelector> GetSelectorForApp(const AppConfig& appConfig)
|
||||
{
|
||||
if(appConfig.paths.count()==1)
|
||||
{
|
||||
return GetSelectorForConfig(appConfig.paths[0], appConfig.debugMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<ListImageSelector> listSelector(new ListImageSelector());
|
||||
for(const auto &path : appConfig.paths)
|
||||
{
|
||||
auto selector = GetSelectorForConfig(path, appConfig.debugMode);
|
||||
listSelector->AddImageSelector(selector,path.timeWindows, path.exclusive);
|
||||
}
|
||||
// new things
|
||||
return listSelector;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector)
|
||||
{
|
||||
QString jsonFile = getAppConfigFilePath(appConfig.configPath);
|
||||
@@ -162,16 +192,13 @@ void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *sw
|
||||
|
||||
if(appConfig.loadTime < QFileInfo(jsonFile).lastModified())
|
||||
{
|
||||
const std::string oldPath = appConfig.path;
|
||||
const std::string oldImageList = appConfig.imageList;
|
||||
|
||||
AppConfig oldConfig = appConfig;
|
||||
appConfig = loadAppConfiguration(appConfig);
|
||||
|
||||
ConfigureWindowFromSettings(w, appConfig);
|
||||
if(appConfig.PathOptionsChanged(oldConfig))
|
||||
{
|
||||
std::unique_ptr<ImageSelector> selector = GetSelectorForConfig(appConfig);
|
||||
std::unique_ptr<ImageSelector> selector = GetSelectorForApp(appConfig);
|
||||
switcher->setImageSelector(selector);
|
||||
}
|
||||
|
||||
@@ -193,7 +220,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
AppConfig appConfig = loadAppConfiguration(commandLineAppConfig);
|
||||
|
||||
if (appConfig.path.empty() && appConfig.imageList.empty())
|
||||
if (appConfig.paths.empty())
|
||||
{
|
||||
std::cout << "Error: Path expected." << std::endl;
|
||||
usage(argv[0]);
|
||||
@@ -210,7 +237,7 @@ int main(int argc, char *argv[])
|
||||
ConfigureWindowFromSettings(w, appConfig);
|
||||
w.show();
|
||||
|
||||
std::unique_ptr<ImageSelector> selector = GetSelectorForConfig(appConfig);
|
||||
std::unique_ptr<ImageSelector> selector = GetSelectorForApp(appConfig);
|
||||
selector->setDebugMode(appConfig.debugMode);
|
||||
|
||||
ImageSwitcher switcher(w, appConfig.rotationSeconds * 1000, selector);
|
||||
|
||||
Reference in New Issue
Block a user