Special command line option classes added

This commit is contained in:
johan 2013-08-11 21:49:11 +02:00
parent 29f6e41923
commit cc3baec022
8 changed files with 559 additions and 306 deletions

View File

@ -54,7 +54,41 @@ void OptionsParser::parse(int argc, const char* argv[]) throw(runtime_error)
for(i = parameters.parameters.begin(); for(i = parameters.parameters.begin();
i != parameters.parameters.end(); i++) i != parameters.parameters.end(); i++)
{ {
if((*i)->receive(state)) break; int n = 0;
try
{
n = (*i)->receive(state);
}
catch(Parameter::ExpectedArgument &)
{
throw Parameter::ExpectedArgument(state.get() + ": expected an argument");
}
catch(Parameter::UnexpectedArgument &)
{
throw Parameter::UnexpectedArgument(state.get() + ": did not expect an argument");
}
catch(Switchable::SwitchingError &)
{
throw Parameter::ParameterRejected(state.get() + ": parameter already set");
}
catch(Parameter::ParameterRejected & pr) {
std::string what = pr.what();
if(what.length())
{
throw Parameter::ParameterRejected(state.get() + ": " + what);
}
throw Parameter::ParameterRejected(state.get() + " (unspecified error)");
}
for (int j = 1; j < n; ++j)
{
state.advance();
}
if(n != 0)
{
break;
}
} }
if(i == parameters.parameters.end()) { if(i == parameters.parameters.end()) {
@ -76,9 +110,8 @@ void OptionsParser::parse(int argc, const char* argv[]) throw(runtime_error)
} }
void OptionsParser::usage() const { void OptionsParser::usage() const {
cerr << "Usage: " << programName() << " arguments" << endl; cerr << fprogramDesc << endl;
cerr << "Usage: " << programName() << " [OPTIONS]" << endl << endl;
cerr << fprogramDesc << endl << endl;
cerr << "Parameters: " << endl; cerr << "Parameters: " << endl;
@ -93,7 +126,6 @@ void OptionsParser::usage() const {
cerr << std::left << (*i)->description() << endl; cerr << std::left << (*i)->description() << endl;
} }
} }
const vector<string>& OptionsParser::getFiles() const { const vector<string>& OptionsParser::getFiles() const {
@ -235,26 +267,6 @@ void PresettableUniquelySwitchable::preset() {
fpreset.set(); fpreset.set();
} }
/*
*
* Class SwitchParameter
*
*
*/
SwitchParameter::SwitchParameter(char shortOption, const char *longOption,
const char* description) : CommonParameter<MultiSwitchable>(shortOption, longOption, description) {}
SwitchParameter::~SwitchParameter() {}
void SwitchParameter::receiveSwitch() throw(Parameter::ParameterRejected) {
set();
}
void SwitchParameter::receiveArgument(const string &arg) throw(Parameter::ParameterRejected) {
throw UnexpectedArgument();
}
/* /*
* *
* PODParameter specializations * PODParameter specializations

View File

@ -203,7 +203,7 @@ protected:
* iterator that technically allows for more complex grammar than what is * iterator that technically allows for more complex grammar than what is
* presently used. * presently used.
*/ */
virtual bool receive(ParserState& state) throw(ParameterRejected) = 0; virtual int receive(ParserState& state) throw(ParameterRejected) = 0;
friend class OptionsParser; friend class OptionsParser;
@ -250,20 +250,9 @@ protected:
* receiveSwitch() or receiveArgument() accordingly. * receiveSwitch() or receiveArgument() accordingly.
* *
* @param state The current argument being parsed. * @param state The current argument being parsed.
* @return The number of parameters taken from the input
*/ */
virtual bool receive(ParserState& state) throw(ParameterRejected); virtual int receive(ParserState& state) throw(ParameterRejected) = 0;
/**
* Called when a parameter does not have an argument, e.g.
* either -f or --foo
*/
virtual void receiveSwitch() throw (ParameterRejected) = 0;
/**
* Called when a parameter does have an argument, .e.g
* -fbar or --foo=bar
*/
virtual void receiveArgument(const std::string& argument) throw (ParameterRejected) = 0;
}; };
/** This class (used as a mixin) defines how a parameter /** This class (used as a mixin) defines how a parameter
@ -344,15 +333,15 @@ private:
/* Parameter that does not take an argument, and throws an exception /* Parameter that does not take an argument, and throws an exception
* if an argument is given */ * if an argument is given */
class SwitchParameter : public CommonParameter<MultiSwitchable> { template<typename SwitchingBehavior=MultiSwitchable>
class SwitchParameter : public CommonParameter<SwitchingBehavior> {
public: public:
SwitchParameter(char shortOption, const char *longOption, SwitchParameter(char shortOption, const char *longOption,
const char* description); const char* description);
virtual ~SwitchParameter(); virtual ~SwitchParameter();
protected: protected:
virtual void receiveSwitch() throw (Parameter::ParameterRejected); virtual int receive(ParserState& state) throw(Parameter::ParameterRejected);
virtual void receiveArgument(const std::string& argument) throw (Parameter::ParameterRejected);
}; };
/** Plain-Old-Data parameter. Performs input validation. /** Plain-Old-Data parameter. Performs input validation.
@ -363,8 +352,8 @@ protected:
* Specifically, you need to specialize validate(). * Specifically, you need to specialize validate().
*/ */
template<typename T> template<typename T, typename SwitchingBehavior=PresettableUniquelySwitchable>
class PODParameter : public CommonParameter<PresettableUniquelySwitchable> { class PODParameter : public CommonParameter<SwitchingBehavior> {
public: public:
PODParameter(char shortOption, const char *longOption, PODParameter(char shortOption, const char *longOption,
const char* description); const char* description);
@ -383,14 +372,14 @@ public:
std::string usageLine() const; std::string usageLine() const;
protected: protected:
virtual int receive(ParserState& state) throw(Parameter::ParameterRejected);
/** Validation function for the data type. /** Validation function for the data type.
* *
* @throw ParameterRejected if the argument does not conform to this data type. * @throw ParameterRejected if the argument does not conform to this data type.
* @return the value corresponding to the argument. * @return the value corresponding to the argument.
*/ */
virtual T validate(const std::string& s) throw (ParameterRejected); virtual T validate(const std::string& s) throw (Parameter::ParameterRejected);
virtual void receiveArgument(const std::string &argument) throw(ParameterRejected);
virtual void receiveSwitch() throw (Parameter::ParameterRejected);
T value; T value;
}; };

View File

@ -53,10 +53,9 @@ template<typename SwitchingBehavior>
std::string CommonParameter<SwitchingBehavior>::usageLine() const { std::string CommonParameter<SwitchingBehavior>::usageLine() const {
std::stringstream strstr; std::stringstream strstr;
strstr.width(10);
if (hasShortOption()) if (hasShortOption())
{ {
strstr << std::left<< std::string("-") + shortOption(); strstr << "-" << shortOption() << ", ";
} }
else else
{ {
@ -68,140 +67,111 @@ std::string CommonParameter<SwitchingBehavior>::usageLine() const {
return strstr.str(); return strstr.str();
} }
/*
*
* Class SwitchParameter
*
*
*/
template<typename SwitchingBehavior> template<typename SwitchingBehavior>
bool CommonParameter<SwitchingBehavior>::receive(ParserState& state) throw(Parameter::ParameterRejected) { SwitchParameter<SwitchingBehavior>::SwitchParameter(char shortOption, const char *longOption,
const char* description) : CommonParameter<SwitchingBehavior>(shortOption, longOption, description) {}
template<typename SwitchingBehavior>
SwitchParameter<SwitchingBehavior>::~SwitchParameter() {}
template<typename SwitchingBehavior>
int SwitchParameter<SwitchingBehavior>::receive(ParserState& state) throw(Parameter::ParameterRejected) {
const std::string arg = state.get(); const std::string arg = state.get();
try {
if(arg.at(0) != '-') return false; if(arg.at(0) != '-') return false;
if(arg.at(1) == '-') { /* Long form parameter */ if ((arg.at(1) == '-' && arg.substr(2) == this->longOption()) ||
try { (this->hasShortOption() && arg.at(1) == this->shortOption() && arg.length() == 2))
unsigned int eq = arg.find_first_of("=");
if(eq == std::string::npos) {
if(arg.substr(2) != longOption())
return false;
this->receiveSwitch();
} else {
if(arg.substr(2, eq-2) != longOption())
return false;
this->receiveArgument(arg.substr(eq+1));
}
return true;
} catch(Parameter::ExpectedArgument &ea) {
throw ExpectedArgument("--" + longOption() + ": expected an argument");
} catch(Parameter::UnexpectedArgument &ua) {
throw UnexpectedArgument("--" + longOption() + ": did not expect an argument");
} catch(Switchable::SwitchingError &e) {
throw ParameterRejected("--" + longOption() + ": parameter already set");
} catch(Parameter::ParameterRejected &pr) {
std::string what = pr.what();
if(what.length())
throw Parameter::ParameterRejected("--" + longOption() + ": " + what);
throw Parameter::ParameterRejected("--" + longOption() + " (unspecified error)");
}
}
else if (hasShortOption())
{ {
try { this->set();
if(arg.at(1) == shortOption()) { return 1;
/* Matched argument on the form -f or -fsomething */
if(arg.length() == 2) { /* -f */
this->receiveSwitch();
return true;
} else { /* -fsomething */
this->receiveArgument(arg.substr(2));
return true;
}
}
} catch(Parameter::ExpectedArgument &ea) {
throw ExpectedArgument(std::string("-") + shortOption() + ": expected an argument");
} catch(Parameter::UnexpectedArgument &ua) {
throw UnexpectedArgument(std::string("-") + shortOption() + ": did not expect an argument");
} catch(Switchable::SwitchingError &e) {
throw ParameterRejected(std::string("-") + shortOption() + ": parameter already set");
}
}
} catch(std::out_of_range& o) {
return false;
} }
return false; return 0;
} }
/* /*
* PODParameter stuff * PODParameter stuff
* *
*/ */
template<typename T> template<typename T, typename SwitchingBehavior>
PODParameter<T>::PODParameter(char shortOption, const char *longOption, PODParameter<T, SwitchingBehavior>::PODParameter(char shortOption, const char *longOption,
const char* description) : CommonParameter<PresettableUniquelySwitchable>(shortOption, longOption, description) {} const char* description) : CommonParameter<PresettableUniquelySwitchable>(shortOption, longOption, description) {}
template<typename T> template<typename T, typename SwitchingBehavior>
PODParameter<T>::~PODParameter() {} PODParameter<T, SwitchingBehavior>::~PODParameter() {}
template<typename T> template<typename T, typename SwitchingBehavior>
PODParameter<T>::operator T() const { return getValue(); } PODParameter<T, SwitchingBehavior>::operator T() const { return getValue(); }
template<typename T> template<typename T, typename SwitchingBehavior>
void PODParameter<T>::setDefault(T value) { void PODParameter<T, SwitchingBehavior>::setDefault(T value) {
PresettableUniquelySwitchable::preset(); PresettableUniquelySwitchable::preset();
this->value = value; this->value = value;
} }
template<typename T> template<typename T, typename SwitchingBehavior>
T PODParameter<T>::getValue() const { T PODParameter<T, SwitchingBehavior>::getValue() const {
if(!isSet()) { if(!this->isSet()) {
throw runtime_error( throw std::runtime_error(
std::string("Attempting to retreive the argument of parameter") + longOption() + " but it hasn't been set!"); std::string("Attempting to retreive the argument of parameter") + this->longOption() + " but it hasn't been set!");
} }
return value; return value;
} }
template<typename T, typename SwitchingBehavior>
template<typename T> std::string PODParameter<T, SwitchingBehavior>::usageLine() const {
std::string PODParameter<T>::usageLine() const {
std::stringstream strstr; std::stringstream strstr;
strstr.width(10); if (this->hasShortOption())
if (hasShortOption())
{ {
strstr << std::left << std::string("-") + shortOption() +"arg"; strstr << "-" << this->shortOption() << ", ";
} }
else else
{ {
strstr << " "; strstr << " ";
} }
strstr.width(20); strstr.width(20);
strstr << std::left << "--" + longOption() + "=arg"; strstr << std::left << "--" + this->longOption() + " <arg>";
return strstr.str(); return strstr.str();
} }
template<typename T> template<typename T, typename SwitchingBehavior>
void PODParameter<T>::receiveSwitch() throw (Parameter::ParameterRejected) { int PODParameter<T, SwitchingBehavior>::receive(ParserState& state) throw(Parameter::ParameterRejected) {
throw Parameter::ExpectedArgument();
const std::string arg = state.get();
if(arg.at(0) != '-') return false;
if((arg.at(1) == '-' && arg.substr(2) == this->longOption()) ||
(this->hasShortOption() && arg.at(1) == this->shortOption() && arg.length() == 2))
{
// retrieve the argument
std::string arg1 = state.peek();
if (arg1.length() == 0)
{
throw Parameter::ExpectedArgument(arg + ": expected an argument");
return 1;
} }
template<typename T> this->set();
void PODParameter<T>::receiveArgument(const std::string &argument) throw(Parameter::ParameterRejected) { value = this->validate(arg1);
set();
value = this->validate(argument); return 2;
} }
return 0;
}
#endif #endif

View File

@ -1,19 +1,22 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
project(hyperion-remote) project(hyperion-remote)
find_package(Qt4 REQUIRED QtCore QtNetwork) find_package(Qt4 REQUIRED QtCore QtGui QtNetwork)
# The following I do not undrstand completely... # The following I do not undrstand completely...
# libQtCore.so uses some hardcoded library path inside which are incorrect after copying the file RPi file system # libQtCore.so uses some hardcoded library path inside which are incorrect after copying the file RPi file system
# Therefor, an extra path is needed on which to find the required libraries # Therefor, an extra path is needed on which to find the required libraries
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf) LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf)
include_directories(${QT_INCLUDE_DIR}) include_directories(${QT_INCLUDES})
set(hyperion-remote_HEADERS) set(hyperion-remote_HEADERS
specialoptions.h
connection.h)
set(hyperion-remote_SOURCES set(hyperion-remote_SOURCES
hyperion-remote.cpp) hyperion-remote.cpp
connection.cpp)
qt4_wrap_cpp(HYPERION_REMOTE_MOC_SOURCES qt4_wrap_cpp(HYPERION_REMOTE_MOC_SOURCES
${hyperion-remote_HEADERS}) ${hyperion-remote_HEADERS})
@ -25,6 +28,7 @@ add_executable(hyperion-remote
qt4_use_modules(hyperion-remote qt4_use_modules(hyperion-remote
Core Core
Gui
Network) Network)
target_link_libraries(hyperion-remote target_link_libraries(hyperion-remote

View File

@ -0,0 +1,71 @@
#include "connection.h"
Connection::Connection(const std::string &address, bool printJson)
{
}
Connection::~Connection()
{
}
bool Connection::setColor(QColor color, int priority, int duration)
{
std::cout << "Set color to " << color.red() << " " << color.green() << " " << color.blue() << std::endl;
return false;
}
bool Connection::setImage(QImage image, int priority, int duration)
{
std::cout << "Set image has size: " << image.width() << "x" << image.height() << std::endl;
return false;
}
bool Connection::listPriorities()
{
std::cout << "List priority channels" << std::endl;
return false;
}
bool Connection::clear(int priority)
{
std::cout << "Clear priority channel " << priority << std::endl;
return false;
}
bool Connection::clearAll()
{
std::cout << "Clear all priority channels" << std::endl;
return false;
}
bool Connection::setThreshold(double red, double green, double blue)
{
return false;
}
bool Connection::setGamma(double red, double green, double blue)
{
return false;
}
bool Connection::setBlacklevel(double red, double green, double blue)
{
return false;
}
bool Connection::setWhitelevel(double red, double green, double blue)
{
return false;
}
bool Connection::sendMessage(const Json::Value &message)
{
if (_printJson)
{
std::cout << "Command:" << std::endl;
std::cout << message << std::endl;
}
return true;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <string>
#include <QColor>
#include <QImage>
#include <json/json.h>
class Connection
{
public:
Connection(const std::string & address, bool printJson);
~Connection();
bool setColor(QColor color, int priority, int duration);
bool setImage(QImage image, int priority, int duration);
bool listPriorities();
bool clear(int priority);
bool clearAll();
bool setThreshold(double red, double green, double blue);
bool setGamma(double red, double green, double blue);
bool setBlacklevel(double red, double green, double blue);
bool setWhitelevel(double red, double green, double blue);
private:
bool sendMessage(const Json::Value & message);
private:
bool _printJson;
};

View File

@ -1,10 +1,25 @@
#include <QDebug> #include <initializer_list>
#include <QCoreApplication> #include <QCoreApplication>
#include <getoptPlusPlus/getoptpp.h> #include <getoptPlusPlus/getoptpp.h>
#include "specialoptions.h"
#include "connection.h"
using namespace vlofgren; using namespace vlofgren;
int count(std::initializer_list<bool> values)
{
int count = 0;
for (auto& value : values) {
if (value)
count++;
}
return count;
}
int main(int argc, const char * argv[]) int main(int argc, const char * argv[])
{ {
// some settings // some settings
@ -15,35 +30,94 @@ int main(int argc, const char * argv[])
ParameterSet & parameters = optionParser.getParameters(); ParameterSet & parameters = optionParser.getParameters();
StringParameter & argAddress = parameters.add<StringParameter> ('a', "address" , QString("Set the address of the hyperion server [default: %1]").arg(defaultServerAddress).toAscii().constData()); StringParameter & argAddress = parameters.add<StringParameter> ('a', "address" , QString("Set the address of the hyperion server [default: %1]").arg(defaultServerAddress).toAscii().constData());
IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority" , QString("Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]").arg(defaultPriority).toAscii().constData()); IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority" , QString("Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]").arg(defaultPriority).toAscii().constData());
IntParameter & argDuration = parameters.add<IntParameter> ('d', "duration" , "Specify how long the leds should be switched on in millseconds. Without this parameter, the leds will be switched on without end time."); IntParameter & argDuration = parameters.add<IntParameter> ('d', "duration" , "Specify how long the leds should be switched on in millseconds [default: infinity]");
StringParameter & argColor = parameters.add<StringParameter>('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)"); ColorParameter & argColor = parameters.add<ColorParameter> ('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)");
StringParameter & argImage = parameters.add<StringParameter>('i', "image" , "Set the leds to the colors according to the given image file"); ImageParameter & argImage = parameters.add<ImageParameter> ('i', "image" , "Set the leds to the colors according to the given image file");
SwitchParameter & argList = parameters.add<SwitchParameter>('l', "list" , "List all priority channels which are in use"); SwitchParameter<> & argList = parameters.add<SwitchParameter<> >('l', "list" , "List all priority channels which are in use");
SwitchParameter & argClear = parameters.add<SwitchParameter>('x', "clear" , "Clear data for the priority channel provided by the -p option"); SwitchParameter<> & argClear = parameters.add<SwitchParameter<> >('x', "clear" , "Clear data for the priority channel provided by the -p option");
SwitchParameter & argClearAll = parameters.add<SwitchParameter>(0x0, "clear-all" , "Clear data for all priority channels"); SwitchParameter<> & argClearAll = parameters.add<SwitchParameter<> >(0x0, "clear-all" , "Clear data for all priority channels");
DoubleParameter & argGamma = parameters.add<DoubleParameter>('g', "gamma" , "Set the gamma of the leds (requires 3 values)"); TransformParameter & argGamma = parameters.add<TransformParameter>('g', "gamma" , "Set the gamma of the leds (requires 3 values)");
DoubleParameter & argThreshold = parameters.add<DoubleParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 values between 0.0 and 1.0)"); TransformParameter & argThreshold = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)");
DoubleParameter & argBlacklevel = parameters.add<DoubleParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 values which are normally between 0.0 and 1.0)"); TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)");
DoubleParameter & argWhitelevel = parameters.add<DoubleParameter>('w', "whitelevel", "Set the whitelevel of the leds (requires 3 values which are normally between 0.0 and 1.0)"); TransformParameter & argWhitelevel = parameters.add<TransformParameter>('w', "whitelevel", "Set the whitelevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)");
SwitchParameter & argPrint = parameters.add<SwitchParameter>(0x0, "print" , "Print the json input and output messages on stdout"); SwitchParameter<> & argPrint = parameters.add<SwitchParameter<> >(0x0, "print" , "Print the json input and output messages on stdout");
SwitchParameter & argHelp = parameters.add<SwitchParameter>('h', "help" , "Show this help message and exit"); SwitchParameter<> & argHelp = parameters.add<SwitchParameter<> >('h', "help" , "Show this help message and exit");
argAddress.setDefault(defaultServerAddress.toStdString());
argPriority.setDefault(defaultPriority);
argDuration.setDefault(-1);
try try
{ {
optionParser.parse(argc, argv); optionParser.parse(argc, argv);
} }
catch (const std::runtime_error & e) catch (const std::runtime_error & e)
{ {
qWarning() << e.what(); std::cerr << e.what() << std::endl;
optionParser.usage();
return 1; return 1;
} }
// check if we need to display the usage
if (argHelp.isSet()) if (argHelp.isSet())
{ {
optionParser.usage(); optionParser.usage();
return 0; return 0;
} }
// check if a color transform is set
bool colorTransform = argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet();
// check if exactly one command was given
int commandCount = count({argColor.isSet(), argImage.isSet(), argList.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform});
if (commandCount != 1)
{
if (commandCount == 0)
{
std::cerr << "No command found. Provide one of the following options:" << std::endl;
}
else
{
std::cerr << "Multiple commands found. Provide one of the following options:" << std::endl;
}
std::cerr << " " << argColor.usageLine() << std::endl;
std::cerr << " " << argImage.usageLine() << std::endl;
std::cerr << " " << argList.usageLine() << std::endl;
std::cerr << " " << argClear.usageLine() << std::endl;
std::cerr << " " << argClearAll.usageLine() << std::endl;
std::cerr << "or one or more of the color transformations:" << std::endl;
std::cerr << " " << argThreshold.usageLine() << std::endl;
std::cerr << " " << argGamma.usageLine() << std::endl;
std::cerr << " " << argBlacklevel.usageLine() << std::endl;
std::cerr << " " << argWhitelevel.usageLine() << std::endl;
return 1;
}
Connection connection(argAddress.getValue(), argPrint.isSet());
// now execute the given command
if (argColor.isSet())
{
connection.setColor(argColor.getValue(), argPriority.getValue(), argDuration.getValue());
}
else if (argImage.isSet())
{
connection.setImage(argImage.getValue(), argPriority.getValue(), argDuration.getValue());
}
else if (argList.isSet())
{
connection.listPriorities();
}
else if (argClear.isSet())
{
connection.clear(argPriority.getValue());
}
else if (argClearAll.isSet())
{
connection.clearAll();
}
else if (colorTransform)
{
}
return 0; return 0;
} }

View File

@ -0,0 +1,102 @@
#pragma once
#include <QColor>
#include <QImage>
#include <getoptPlusPlus/getoptpp.h>
struct ColorTransform
{
double valueRed;
double valueGreen;
double valueBlue;
};
typedef vlofgren::PODParameter<QColor> ColorParameter;
typedef vlofgren::PODParameter<QImage> ImageParameter;
typedef vlofgren::PODParameter<ColorTransform> TransformParameter;
namespace vlofgren {
template<>
QColor ColorParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{
// Check if we can create the color by name
QColor color(s.c_str());
if (color.isValid())
{
return color;
}
// check if we can create the color by hex RRGGBB value
if (s.length() == 6 && isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]))
{
bool ok = true;
int rgb[3];
for (int i = 0; i < 3 && ok; ++i)
{
QString colorComponent(s.substr(2*i, 2).c_str());
rgb[i] = colorComponent.toInt(&ok, 16);
}
// check if all components parsed succesfully
if (ok)
{
color.setRgb(rgb[0], rgb[1], rgb[2]);
return color;
}
}
std::stringstream errorMessage;
errorMessage << "Invalid color. A color is specified by a six lettered RRGGBB hex value or one of the following names:";
foreach (const QString & colorname, QColor::colorNames()) {
errorMessage << "\n " << colorname.toStdString();
}
throw Parameter::ParameterRejected(errorMessage.str());
return color;
}
template<>
QImage ImageParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{
QImage image(s.c_str());
if (image.isNull())
{
std::stringstream errorMessage;
errorMessage << "File " << s << " could not be opened as an image";
throw Parameter::ParameterRejected(errorMessage.str());
}
return image;
}
template<>
ColorTransform TransformParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{
ColorTransform transform;
// s should be split in 3 parts
// seperators are either a ',' or a space
QStringList components = QString(s.c_str()).split(" ", QString::SkipEmptyParts);
if (components.size() == 3)
{
bool ok1, ok2, ok3;
transform.valueRed = components[0].toDouble(&ok1);
transform.valueGreen = components[1].toDouble(&ok2);
transform.valueBlue = components[2].toDouble(&ok3);
if (ok1 && ok2 && ok3)
{
return transform;
}
}
std::stringstream errorMessage;
errorMessage << "Argument " << s << " can not be parsed to 3 double values";
throw Parameter::ParameterRejected(errorMessage.str());
return transform;
}
}