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
00073 class QVPropertyHolder
00074 {
00075 public:
00108 typedef enum {AsynchronousLink,SynchronousLink} LinkType;
00109
00114 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2} PropertyInputOutputFlag;
00115 Q_DECLARE_FLAGS(PropertyInputOutputFlags, PropertyInputOutputFlag)
00116
00117
00118 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00119 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00121
00125 QVPropertyHolder(const QString name = QString());
00126
00132 virtual ~QVPropertyHolder();
00133
00137 void setName(const QString name);
00138
00141 const QString getName() const;
00142
00148 QList<QString> getPropertyList() const;
00149
00156 template <class Type> QList<QString> getPropertyListByType() const
00157 {
00158 QList<QString> result;
00159 QList<QString> names = variants.keys();
00160
00161 for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00162 if(isType<Type>(*i))
00163 result.append(*i);
00164
00165 return result;
00166 }
00167
00176 template <class Type> bool isType(QString name,bool *ok = NULL) const
00177 {
00178 if(not checkExists(name,"QVPropertyHolder::propertyIsType()"))
00179 {
00180 if(ok != NULL) *ok = FALSE;
00181 return FALSE;
00182 }
00183 if(ok != NULL) *ok = TRUE;
00184 QVariant::Type type = QVariant::fromValue(Type()).type();
00185 if ((type != QVariant::UserType) && (variants[name].type() == type))
00186 return TRUE;
00187 if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00188 return TRUE;
00189 return FALSE;
00190 }
00191
00196 bool containsProperty(const QString name) const;
00197
00206 QVariant::Type getPropertyType(const QString name, bool *ok = NULL) const;
00207
00215 template <class Type> bool addProperty(const QString name,
00216 const PropertyInputOutputFlags flags = inputFlag,
00217 const Type & value = Type(), const QString info = QString("(Info not available)"))
00218 {
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 if (addPropertyFromQVariant(name, flags, QVariant::fromValue(value), info))
00232 setPropertyFromArguments<Type>(name);
00233 else
00234 return false;
00235
00236 return true;
00237 }
00238
00248 template <class Type> bool addProperty(const QString name,
00249 const PropertyInputOutputFlags flags,
00250 const Type & value, const QString info,
00251 const Type & minValue, const Type & maxValue)
00252 {
00253 addProperty<Type>(name, flags, value, info);
00254 setPropertyRange2<Type>(name, minValue, maxValue);
00255 return TRUE;
00256 }
00257
00262 bool removeProperty(const QString name);
00263
00265 bool setPropertyRange(const QString name, const double & minimum, const double & maximum);
00266
00268 bool setPropertyRange(QString name, int & minimum, int & maximum);
00269
00274 bool hasRange(const QString name);
00275
00280 bool isInput(const QString name);
00281
00286 PropertyInputOutputFlags getPropertyFlags(const QString name) { return io_flags[name]; }
00287
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
00449 bool linkProperty(QString sourcePropertyName, QVPropertyHolder *destinyHolder, QString destinyPropertyName, LinkType linkType);
00450
00456 void unlink();
00457
00458 protected:
00459
00460 template <class Type> bool setPropertyRange2(const QString name, const Type & minimum, const Type & maximum)
00461 {
00462 if(not checkExists(name,"QVPropertyHolder::setPropertyRange()"))
00463 return FALSE;
00464 if(minimum <= getPropertyValue<Type>(name) and
00465 maximum >= getPropertyValue<Type>(name))
00466 {
00467 this->minimum[name] = QVariant::fromValue(minimum);
00468 this->maximum[name] = QVariant::fromValue(maximum);
00469 return TRUE;
00470 } else {
00471 QString str = "QVPropertyHolder::setPropertyRange(): property " +
00472 name + " in holder " + getName() + " has value " +
00473 QString("%1").arg(getPropertyValue<Type>(name)) +
00474 ", which is not valid for the range [" +
00475 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00476 setLastError(str);
00477 if(qvApp->isRunning()) {
00478 std::cerr << qPrintable("Warning: " + str + "\n");
00479 }
00480 return FALSE;
00481 }
00482 }
00483
00491 void readInputProperties();
00492
00503 void writeOutputProperties();
00504
00544 template <class Type> bool parseArgument(const QString parameter, const QString value);
00545
00554 void setLastError(QString str) const;
00555
00563 bool addPropertyFromQVariant(const QString &name, const PropertyInputOutputFlags flags, QVariant variant, const QString info)
00564 {
00565 if(not checkIsNewProperty(name,"QVPropertyHolder::addProperty()"))
00566 return FALSE;
00567 insertion_order.push_back(name);
00568 _info[name] = info;
00569 io_flags[name] = flags;
00570 link_flags[name] = noLinkFlag;
00571
00572 variants[name] = variant;
00573 return TRUE;
00574 }
00575
00576
00577 private:
00578 QString name;
00579 mutable QString errorString;
00580 QMap<QString, QVariant> variants,safelyCopiedVariants;
00581 QMap<QString, QVariant> minimum, maximum;
00582 QMap<QString, QString> _info;
00583 QMap<QString, PropertyInputOutputFlags> io_flags;
00584 QMap<QString, PropertyLinkFlags> link_flags;
00585 QList<QString> insertion_order;
00586
00587
00588 QReadWriteLock RWLock;
00589 class QVPropertyHolderLink {
00590 public:
00591 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) {
00592
00593 SyncSemaphoreIn.release();
00594
00595 };
00596 QVPropertyHolder *qvp_orig;
00597 QString prop_orig;
00598 QVPropertyHolder *qvp_dest;
00599 QString prop_dest;
00600 LinkType link_type;
00601 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00602 bool markedForDeletion;
00603 };
00604 QMap<QString, QVPropertyHolderLink* > inputLinks;
00605 QMap<QString, QList<QVPropertyHolderLink*> > outputLinks;
00606
00607 template <class Type> bool setPropertyFromArguments(QString propertyName)
00608 {
00609 QStringList arguments = qvApp->arguments();
00610
00611 QMutableStringListIterator iterator(arguments);
00612 while (iterator.hasNext())
00613 {
00614 QString argument = iterator.next();
00615
00616
00617
00618 if (argument.contains(QRegExp("^--")))
00619 {
00620 QString propertyHolderName(argument), parameter(argument), value(argument);
00621
00622
00623
00624 if (argument.contains(QRegExp("^--[^=]+:")))
00625 {
00626 propertyHolderName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00627 if(propertyHolderName != getName())
00628 continue;
00629 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00630 }
00631 else
00632 {
00633 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00634 }
00635 if(parameter != propertyName)
00636 continue;
00637
00638 value.remove(QRegExp("^--[^=]*="));
00639 if(parseArgument<Type>(parameter,value))
00640 {
00641 if(not isInput(propertyName))
00642 {
00643 QString str = QString("QVPropertyHolder::setPropertyFromArguments():")
00644 + QString(" property ") + propertyName
00645 + QString(" in holder ") + getName()
00646 + QString(" is not of Input type, and cannot be parsed.");
00647 setLastError(str);
00648
00649 }
00650 qvApp->setArgumentAsUsed(argument);
00651 return TRUE;
00652 }
00653 }
00654 }
00655
00656 return FALSE;
00657 }
00658
00659 bool correctRange(const QString name, const double & value) const;
00660
00661
00662 bool correctRange(const char *name, const int & value) const;
00663 bool correctRange(QString name, const int & value) const;
00664
00665
00666 template <typename T> bool correctRange(const QString parameter, const T & value) {
00667 Q_UNUSED(parameter);
00668 Q_UNUSED(value);
00669 return TRUE;
00670 }
00671
00672 bool checkExists(const QString name, const QString methodname) const;
00673 bool checkIsNewProperty(const QString name, const QString methodname) const;
00674 };
00675
00676 template <class Type> bool QVPropertyHolder::parseArgument(const QString parameter, const QString value)
00677 {
00678 errorString = "QVPropertyHolder::parseArgument(): holder " + getName() +
00679 ": parameter " + parameter +
00680 " has an unknown type to command line parser " +
00681 QString("(trying to parse value %1)").arg(value) ;
00682 return FALSE;
00683 }
00684
00685 template <> bool QVPropertyHolder::parseArgument<bool>(const QString parameter, const QString value);
00686
00687 template <> bool QVPropertyHolder::parseArgument<int>(const QString parameter, const QString value);
00688
00689 template <> bool QVPropertyHolder::parseArgument<double>(const QString parameter, const QString value);
00690
00691 template <> bool QVPropertyHolder::parseArgument<QString>(const QString parameter, const QString value);
00692
00693 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyHolder::PropertyInputOutputFlags)
00694 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyHolder::PropertyLinkFlags)
00695
00696 #endif