00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #ifndef QVPROPERTYHOLDER_H
00026 #define QVPROPERTYHOLDER_H
00027
00028 #include <QStringList>
00029 #include <QVariant>
00030 #include <QRegExp>
00031 #include <QSet>
00032 #include <QReadWriteLock>
00033 #include <QSemaphore>
00034 #include <QDebug>
00035
00036 #include <iostream>
00037
00038 #include <qvcore/qvapplication.h>
00039
00040 #define READ_PROPERTY(HOLDER, TYPE, NAME, VARIABLE) TYPE VARIABLE = HOLDER->getPropertyValue<TYPE>(NAME);
00041 #define READ_PROPERTY_MAX(HOLDER, TYPE, NAME, VARIABLE) TYPE VARIABLE = HOLDER->getPropertyMaximum<TYPE>(NAME);
00042 #define READ_PROPERTY_MIN(HOLDER, TYPE, NAME, VARIABLE) TYPE VARIABLE = HOLDER->getPropertyMinimum<TYPE>(NAME);
00043
00071 class QVPropertyHolder
00072 {
00073 public:
00106 typedef enum {AsynchronousLink,SynchronousLink} LinkType;
00107
00112 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2} PropertyInputOutputFlag;
00113 Q_DECLARE_FLAGS(PropertyInputOutputFlags, PropertyInputOutputFlag)
00114
00115
00116 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00117 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00119
00123 QVPropertyHolder(const QString name = QString());
00124
00130 virtual ~QVPropertyHolder();
00131
00135 void setName(const QString name);
00136
00139 const QString getName() const;
00140
00146 QList<QString> getPropertyList() const;
00147
00154 template <class Type> QList<QString> getPropertyListByType() const
00155 {
00156 QList<QString> result;
00157 QList<QString> names = variants.keys();
00158
00159 for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00160 if(isType<Type>(*i))
00161 result.append(*i);
00162
00163 return result;
00164 }
00165
00174 template <class Type> bool isType(QString name,bool *ok = NULL) const
00175 {
00176 if(not checkExists(name,"QVPropertyHolder::propertyIsType()"))
00177 {
00178 if(ok != NULL) *ok = FALSE;
00179 return FALSE;
00180 }
00181 if(ok != NULL) *ok = TRUE;
00182 QVariant::Type type = QVariant::fromValue(Type()).type();
00183 if ((type != QVariant::UserType) && (variants[name].type() == type))
00184 return TRUE;
00185 if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00186 return TRUE;
00187 return FALSE;
00188 }
00189
00194 bool containsProperty(const QString name) const;
00195
00204 QVariant::Type getPropertyType(const QString name, bool *ok = NULL) const;
00205
00213 template <class Type> bool addProperty(const QString name,
00214 const PropertyInputOutputFlags flags = inputFlag,
00215 const Type & value = Type(), const QString info = QString("(Info not available)"))
00216 {
00217 if(not checkIsNewProperty(name,"QVPropertyHolder::addProperty()"))
00218 return FALSE;
00219 insertion_order.push_back(name);
00220 _info[name] = info;
00221 io_flags[name] = flags;
00222 link_flags[name] = noLinkFlag;
00223
00224
00225
00226 variants[name] = QVariant::fromValue(value);
00227 setPropertyFromArguments<Type>(name);
00228 return TRUE;
00229 }
00230
00240 template <class Type> bool addProperty(const QString name,
00241 const PropertyInputOutputFlags flags,
00242 const Type & value, const QString info,
00243 const Type & minValue, const Type & maxValue)
00244 {
00245 addProperty<Type>(name, flags, value, info);
00246 setPropertyRange2<Type>(name, minValue, maxValue);
00247 return TRUE;
00248 }
00249
00254 bool removeProperty(const QString name);
00255
00267 bool setPropertyRange(const QString name, const double & minimum, const double & maximum);
00268
00269
00272 bool setPropertyRange(const char *name, int & minimum, int & maximum);
00274 bool setPropertyRange(QString name, int & minimum, int & maximum);
00276
00281 bool hasRange(const QString name);
00282
00287 bool isInput(const QString name);
00288
00293 bool isOutput(const QString name);
00294
00299 bool isLinkedInput(const QString name);
00300
00305 bool isLinkedOutput(const QString name);
00306
00317 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00318 {
00319 if(not checkExists(name,"QVPropertyHolder::setPropertyValue()"))
00320 return FALSE;
00321 else if (not correctRange(name,value))
00322 return FALSE;
00323 else {
00324 variants[name] = QVariant::fromValue<Type>(value);
00325 return TRUE;
00326 }
00327 }
00328
00335 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00336 {
00337 if (not checkExists(name,"QVPropertyHolder::getPropertyValue()"))
00338 if(ok != NULL) *ok = FALSE;
00339 else
00340 if(ok != NULL) *ok = TRUE;
00341 return variants[name].value<Type>();
00342 }
00343
00350 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00351
00358 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00359 {
00360 if(not checkExists(name,"QVPropertyHolder::getPropertyMaximum()"))
00361 if(ok != NULL) *ok = FALSE;
00362 else if(not maximum.contains(name) and not minimum.contains(name))
00363 {
00364 QString str = QString("QVPropertyHolder::getPropertyMaximum():")
00365 + QString(" property ") + name
00366 + QString(" has no maximum value in ")
00367 + QString("holder ") + getName() + QString(".");
00368 setLastError(str);
00369 if(qvApp->isRunning()) {
00370 std::cerr << qPrintable("Warning: " + str + "\n");
00371 }
00372 if(ok != NULL) *ok = FALSE;
00373 }
00374 else
00375 if(ok != NULL) *ok = TRUE;
00376 return maximum[name].value<Type>();
00377 }
00378
00385 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00386 {
00387 if(not checkExists(name,"QVPropertyHolder::getPropertyMinimum()"))
00388 if(ok != NULL) *ok = FALSE;
00389 else if(not maximum.contains(name) and not minimum.contains(name))
00390 {
00391 QString str = QString("QVPropertyHolder::getPropertyMinimum():")
00392 + QString(" property ") + name
00393 + QString(" has no minimum value in ")
00394 + QString("holder ") + getName() + QString(".");
00395 setLastError(str);
00396 if(qvApp->isRunning()) {
00397 std::cerr << qPrintable("Warning: " + str + "\n");
00398 }
00399 if(ok != NULL) *ok = FALSE;
00400 }
00401 else
00402 if(ok != NULL) *ok = TRUE;
00403 return minimum[name].value<Type>();
00404 }
00405
00413 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00414
00420 QString getLastError() const;
00421
00429 const QString infoInputProperties() const;
00430
00442 bool linkProperty(QString prop_orig,QVPropertyHolder *qvp_dest,QString prop_dest,LinkType link_type);
00443
00449 void unlink();
00450
00451 protected:
00452
00453 template <class Type> bool setPropertyRange2(const QString name, const Type & minimum, const Type & maximum)
00454 {
00455 if(not checkExists(name,"QVPropertyHolder::setPropertyRange()"))
00456 return FALSE;
00457 if(minimum <= getPropertyValue<Type>(name) and
00458 maximum >= getPropertyValue<Type>(name))
00459 {
00460 this->minimum[name] = QVariant::fromValue(minimum);
00461 this->maximum[name] = QVariant::fromValue(maximum);
00462 return TRUE;
00463 } else {
00464 QString str = "QVPropertyHolder::setPropertyRange(): property " +
00465 name + " in holder " + getName() + " has value " +
00466 QString("%1").arg(getPropertyValue<Type>(name)) +
00467 ", which is not valid for the range [" +
00468 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00469 setLastError(str);
00470 if(qvApp->isRunning()) {
00471 std::cerr << qPrintable("Warning: " + str + "\n");
00472 }
00473 return FALSE;
00474 }
00475 }
00476
00485 void readInputProperties();
00486
00498 void writeOutputProperties();
00499
00539 template <class Type> bool parseArgument(const QString parameter, const QString value);
00540
00549 void setLastError(QString str) const;
00550
00551 private:
00552 QString name;
00553 mutable QString errorString;
00554 QMap<QString, QVariant> variants,safelyCopiedVariants;
00555 QMap<QString, QVariant> minimum, maximum;
00556 QMap<QString, QString> _info;
00557 QMap<QString, PropertyInputOutputFlags> io_flags;
00558 QMap<QString, PropertyLinkFlags> link_flags;
00559 QList<QString> insertion_order;
00560
00561 QReadWriteLock RWLock;
00562 class QVPropertyHolderLink {
00563 public:
00564 QVPropertyHolderLink(QVPropertyHolder *_qvp_orig,QString _prop_orig,QVPropertyHolder *_qvp_dest,QString _prop_dest,LinkType _link_type) : qvp_orig(_qvp_orig), prop_orig(_prop_orig), qvp_dest(_qvp_dest), prop_dest(_prop_dest), link_type(_link_type), markedForDeletion(FALSE) {
00565
00566 SyncSemaphoreIn.release();
00567
00568 };
00569 QVPropertyHolder *qvp_orig;
00570 QString prop_orig;
00571 QVPropertyHolder *qvp_dest;
00572 QString prop_dest;
00573 LinkType link_type;
00574 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00575 bool markedForDeletion;
00576 };
00577 QMap<QString, QVPropertyHolderLink* > inputLinks;
00578 QMap<QString, QList<QVPropertyHolderLink*> > outputLinks;
00579
00580 template <class Type> bool setPropertyFromArguments(QString propertyName)
00581 {
00582 QStringList arguments = qvApp->arguments();
00583
00584 QMutableStringListIterator iterator(arguments);
00585 while (iterator.hasNext())
00586 {
00587 QString argument = iterator.next();
00588
00589
00590
00591 if (argument.contains(QRegExp("^--")))
00592 {
00593 QString propertyHolderName(argument), parameter(argument), value(argument);
00594
00595
00596
00597 if (argument.contains(QRegExp("^--[^=]+:")))
00598 {
00599 propertyHolderName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00600 if(propertyHolderName != getName())
00601 continue;
00602 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00603 }
00604 else
00605 {
00606 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00607 }
00608 if(parameter != propertyName)
00609 continue;
00610
00611 value.remove(QRegExp("^--[^=]*="));
00612
00613
00614
00615
00616
00617 if(parseArgument<Type>(parameter,value))
00618 {
00619 if(not isInput(propertyName))
00620 {
00621 QString str = QString("QVPropertyHolder::setPropertyFromArguments():")
00622 + QString(" property ") + propertyName
00623 + QString(" in holder ") + getName()
00624 + QString(" is not of Input type, and cannot be parsed.");
00625 setLastError(str);
00626
00627 }
00628 qvApp->setArgumentAsUsed(argument);
00629 return TRUE;
00630 }
00631 }
00632 }
00633
00634 return FALSE;
00635 }
00636
00637 bool correctRange(const QString name, const double & value) const;
00638
00639
00640 bool correctRange(const char *name, const int & value) const;
00641 bool correctRange(QString name, const int & value) const;
00642
00643
00644 template <typename T> bool correctRange(const QString parameter, const T & value) {
00645 Q_UNUSED(parameter);
00646 Q_UNUSED(value);
00647 return TRUE;
00648 }
00649
00650 bool checkExists(const QString name, const QString methodname) const;
00651 bool checkIsNewProperty(const QString name, const QString methodname) const;
00652 };
00653
00654 template <class Type> bool QVPropertyHolder::parseArgument(const QString parameter, const QString value)
00655 {
00656 errorString = "QVPropertyHolder::parseArgument(): holder " + getName() +
00657 ": parameter " + parameter +
00658 " has an unknown type to command line parser " +
00659 QString("(trying to parse value %1)").arg(value) ;
00660 return FALSE;
00661 }
00662
00663 template <> bool QVPropertyHolder::parseArgument<bool>(const QString parameter, const QString value);
00664
00665 template <> bool QVPropertyHolder::parseArgument<int>(const QString parameter, const QString value);
00666
00667 template <> bool QVPropertyHolder::parseArgument<double>(const QString parameter, const QString value);
00668
00669 template <> bool QVPropertyHolder::parseArgument<QString>(const QString parameter, const QString value);
00670
00671 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyHolder::PropertyInputOutputFlags)
00672 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyHolder::PropertyLinkFlags)
00673
00674 #endif