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
00041
00042
00043
00073 class QVPropertyContainer
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 QVPropertyContainer(const QString name = QString());
00126
00132 virtual ~QVPropertyContainer();
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,"QVPropertyContainer::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 if (addPropertyFromQVariant(name, flags, QVariant::fromValue(value), info))
00220 setPropertyFromArguments<Type>(name);
00221 else
00222 return FALSE;
00223
00224 return TRUE;
00225 }
00226
00236 template <class Type> bool addProperty(const QString name,
00237 const PropertyInputOutputFlags flags,
00238 const Type & value, const QString info,
00239 const Type & minValue, const Type & maxValue)
00240 {
00241 addProperty<Type>(name, flags, value, info);
00242 setPropertyRange2<Type>(name, minValue, maxValue);
00243 return TRUE;
00244 }
00245
00253 bool addPropertyFromQVariant(const QString &name, const PropertyInputOutputFlags flags, QVariant variant, const QString info)
00254 {
00255
00256 if(not checkIsNewProperty(name,"QVPropertyContainer::addProperty()"))
00257 return FALSE;
00258 insertion_order.push_back(name);
00259
00260 _info[name] = info;
00261 io_flags[name] = flags;
00262 link_flags[name] = noLinkFlag;
00263
00264 variants[name] = variant;
00265 return TRUE;
00266 }
00267
00272 bool removeProperty(const QString name);
00273
00275 bool setPropertyRange(const QString name, const double & minimum, const double & maximum);
00276
00278 bool setPropertyRange(QString name, int & minimum, int & maximum);
00279
00284 bool hasRange(const QString name) const;
00285
00290 PropertyInputOutputFlags getPropertyFlags(const QString name) { return io_flags[name]; }
00291
00296 bool isInput(const QString name) const;
00297
00302 bool isOutput(const QString name) const;
00303
00308 bool isLinkedInput(const QString name) const;
00309
00314 bool isLinkedOutput(const QString name) const;
00315
00326 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00327 {
00328 if(not checkExists(name,"QVPropertyContainer::setPropertyValue()"))
00329 return FALSE;
00330 else if (not correctRange(name,value))
00331 return FALSE;
00332 else {
00333 variants[name] = QVariant::fromValue<Type>(value);
00334 return TRUE;
00335 }
00336 }
00337
00344 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00345 {
00346 if (not checkExists(name,"QVPropertyContainer::getPropertyValue()"))
00347 if(ok != NULL) *ok = FALSE;
00348 else
00349 if(ok != NULL) *ok = TRUE;
00350 return variants[name].value<Type>();
00351 }
00352
00359 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00360
00367 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00368 {
00369 if(not checkExists(name,"QVPropertyContainer::getPropertyMaximum()"))
00370 if(ok != NULL) *ok = FALSE;
00371 else if(not maximum.contains(name) and not minimum.contains(name))
00372 {
00373 QString str = QString("QVPropertyContainer::getPropertyMaximum():")
00374 + QString(" property ") + name
00375 + QString(" has no maximum value in ")
00376 + QString("holder ") + getName() + QString(".");
00377 setLastError(str);
00378 if(qvApp->isRunning()) {
00379 std::cerr << qPrintable("Warning: " + str + "\n");
00380 }
00381 if(ok != NULL) *ok = FALSE;
00382 }
00383 else
00384 if(ok != NULL) *ok = TRUE;
00385 return maximum[name].value<Type>();
00386 }
00387
00394 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00395 {
00396 if(not checkExists(name,"QVPropertyContainer::getPropertyMinimum()"))
00397 if(ok != NULL) *ok = FALSE;
00398 else if(not maximum.contains(name) and not minimum.contains(name))
00399 {
00400 QString str = QString("QVPropertyContainer::getPropertyMinimum():")
00401 + QString(" property ") + name
00402 + QString(" has no minimum value in ")
00403 + QString("holder ") + getName() + QString(".");
00404 setLastError(str);
00405 if(qvApp->isRunning()) {
00406 std::cerr << qPrintable("Warning: " + str + "\n");
00407 }
00408 if(ok != NULL) *ok = FALSE;
00409 }
00410 else
00411 if(ok != NULL) *ok = TRUE;
00412 return minimum[name].value<Type>();
00413 }
00414
00422 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00423
00429 QString getLastError() const;
00430
00438 const QString infoInputProperties() const;
00439
00458 bool linkProperty(QString sourcePropertyName, QVPropertyContainer *destinyContainer, QString destinyPropertyName, LinkType linkType);
00459
00465 void unlink();
00466
00467 protected:
00468
00469 template <class Type> bool setPropertyRange2(const QString name, const Type & minimum, const Type & maximum)
00470 {
00471 if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00472 return FALSE;
00473 if(minimum <= getPropertyValue<Type>(name) and
00474 maximum >= getPropertyValue<Type>(name))
00475 {
00476 this->minimum[name] = QVariant::fromValue(minimum);
00477 this->maximum[name] = QVariant::fromValue(maximum);
00478 return TRUE;
00479 } else {
00480 QString str = "QVPropertyContainer::setPropertyRange(): property " +
00481 name + " in holder " + getName() + " has value " +
00482 QString("%1").arg(getPropertyValue<Type>(name)) +
00483 ", which is not valid for the range [" +
00484 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00485 setLastError(str);
00486 if(qvApp->isRunning()) {
00487 std::cerr << qPrintable("Warning: " + str + "\n");
00488 }
00489 return FALSE;
00490 }
00491 }
00492
00500 void readInputProperties();
00501
00512 void writeOutputProperties();
00513
00553 template <class Type> bool parseArgument(const QString parameter, const QString value);
00554
00563 void setLastError(QString str) const;
00564
00565 private:
00566 QString name;
00567 mutable QString errorString;
00568 QMap<QString, QVariant> variants,safelyCopiedVariants;
00569 QMap<QString, QVariant> minimum, maximum;
00570 QMap<QString, QString> _info;
00571 QMap<QString, PropertyInputOutputFlags> io_flags;
00572 QMap<QString, PropertyLinkFlags> link_flags;
00573 QList<QString> insertion_order;
00574
00575
00576 QReadWriteLock RWLock;
00577 class QVPropertyContainerLink {
00578 public:
00579 QVPropertyContainerLink(QVPropertyContainer *_qvp_orig,QString _prop_orig,QVPropertyContainer *_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) {
00580
00581 SyncSemaphoreIn.release();
00582
00583 };
00584 QVPropertyContainer *qvp_orig;
00585 QString prop_orig;
00586 QVPropertyContainer *qvp_dest;
00587 QString prop_dest;
00588 LinkType link_type;
00589 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00590 bool markedForDeletion;
00591 };
00592 QMap<QString, QVPropertyContainerLink* > inputLinks;
00593 QMap<QString, QList<QVPropertyContainerLink*> > outputLinks;
00594
00595 template <class Type> bool setPropertyFromArguments(QString propertyName)
00596 {
00597 QStringList arguments = qvApp->arguments();
00598
00599 QMutableStringListIterator iterator(arguments);
00600 while (iterator.hasNext())
00601 {
00602 QString argument = iterator.next();
00603
00604
00605
00606 if (argument.contains(QRegExp("^--")))
00607 {
00608 QString propertyContainerName(argument), parameter(argument), value(argument);
00609
00610
00611
00612 if (argument.contains(QRegExp("^--[^=]+:")))
00613 {
00614 propertyContainerName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00615 if(propertyContainerName != getName())
00616 continue;
00617 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00618 }
00619 else
00620 {
00621 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00622 }
00623 if(parameter != propertyName)
00624 continue;
00625
00626 value.remove(QRegExp("^--[^=]*="));
00627 if(parseArgument<Type>(parameter,value))
00628 {
00629 if(not isInput(propertyName))
00630 {
00631 QString str = QString("QVPropertyContainer::setPropertyFromArguments():")
00632 + QString(" property ") + propertyName
00633 + QString(" in holder ") + getName()
00634 + QString(" is not of Input type, and cannot be parsed.");
00635 setLastError(str);
00636
00637 }
00638 qvApp->setArgumentAsUsed(argument);
00639 return TRUE;
00640 }
00641 }
00642 }
00643
00644 return FALSE;
00645 }
00646
00647 bool correctRange(const QString name, const double & value) const;
00648
00649
00650 bool correctRange(const char *name, const int & value) const;
00651 bool correctRange(QString name, const int & value) const;
00652
00653
00654 template <typename T> bool correctRange(const QString parameter, const T & value) {
00655 Q_UNUSED(parameter);
00656 Q_UNUSED(value);
00657 return TRUE;
00658 }
00659
00660 bool checkExists(const QString name, const QString methodname) const;
00661 bool checkIsNewProperty(const QString name, const QString methodname) const;
00662 };
00663
00664 template <class Type> bool QVPropertyContainer::parseArgument(const QString parameter, const QString value)
00665 {
00666 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00667 ": parameter " + parameter +
00668 " has an unknown type to command line parser " +
00669 QString("(trying to parse value %1)").arg(value) ;
00670 return FALSE;
00671 }
00672
00673 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value);
00674
00675 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value);
00676
00677 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value);
00678
00679 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value);
00680
00681 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyInputOutputFlags)
00682 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyLinkFlags)
00683
00684 #endif