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
00051 class QVPropertyContainer
00052 {
00053 public:
00086 typedef enum {AsynchronousLink,SynchronousLink} LinkType;
00087
00092 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2, guiInvisible=0x4, internalProp=0x8} PropertyFlag;
00093 Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
00094
00095 #ifndef DOXYGEN_IGNORE_THIS
00096 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00097 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00098 #endif
00099
00103 QVPropertyContainer(const QString name = QString());
00104
00108 QVPropertyContainer(const QVPropertyContainer &cont): name(cont.name), ident(cont.ident), errorString(cont.errorString), variants(cont.variants),
00109 safelyCopiedVariants(cont.safelyCopiedVariants), minimum(cont.minimum), maximum(cont.maximum), _info(cont._info), io_flags(cont.io_flags),
00110 link_flags(cont.link_flags), insertion_order(cont.insertion_order), RWLock(), inputLinks(cont.inputLinks), outputLinks(cont.outputLinks) { }
00111
00115 QVPropertyContainer & operator=(const QVPropertyContainer &cont);
00116
00122 virtual ~QVPropertyContainer();
00123
00127 void setName(const QString name);
00128
00131 const QString getName() const;
00132
00135 const uint getId() const;
00136
00142 bool operator==(const QVPropertyContainer &cont) const;
00143
00149 QList<QString> getPropertyList() const;
00150
00157 template <class Type> QList<QString> getPropertyListByType() const
00158 {
00159 QList<QString> result;
00160 QList<QString> names = variants.keys();
00161
00162 for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00163 if(isType<Type>(*i))
00164 result.append(*i);
00165
00166 return result;
00167 }
00168
00177 template <class Type> bool isType(QString name,bool *ok = NULL) const
00178 {
00179 if(not checkExists(name,"QVPropertyContainer::propertyIsType()"))
00180 {
00181 if(ok != NULL) *ok = FALSE;
00182 return FALSE;
00183 }
00184 if(ok != NULL) *ok = TRUE;
00185 QVariant::Type type = QVariant::fromValue(Type()).type();
00186 if ((type != QVariant::UserType) && (variants[name].type() == type))
00187 return TRUE;
00188 if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00189 return TRUE;
00190 return FALSE;
00191 }
00192
00197 bool containsProperty(const QString name) const;
00198
00206 int getPropertyType(const QString name, bool *ok = NULL) const;
00207
00215 template <class Type> bool addProperty(const QString name,
00216 const PropertyFlags 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 PropertyFlags 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 PropertyFlags 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 PropertyFlags 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 isGUIInvisible(const QString name) const;
00309
00314 bool isLinkedInput(const QString name) const;
00315
00320 bool isLinkedOutput(const QString name) const;
00321
00332 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00333 {
00334 if(not checkExists(name,"QVPropertyContainer::setPropertyValue()"))
00335 return FALSE;
00336 else if (not correctRange(name,value))
00337 return FALSE;
00338 else {
00339 variants[name] = QVariant::fromValue<Type>(value);
00340 return TRUE;
00341 }
00342 }
00343
00350 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00351 {
00352 if (not checkExists(name,"QVPropertyContainer::getPropertyValue()"))
00353 if(ok != NULL) *ok = FALSE;
00354 else
00355 if(ok != NULL) *ok = TRUE;
00356 return variants[name].value<Type>();
00357 }
00358
00365 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00366
00373 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00374 {
00375 if(not checkExists(name,"QVPropertyContainer::getPropertyMaximum()"))
00376 if(ok != NULL) *ok = FALSE;
00377 else if(not maximum.contains(name) and not minimum.contains(name))
00378 {
00379 QString str = QString("QVPropertyContainer::getPropertyMaximum():")
00380 + QString(" property ") + name
00381 + QString(" has no maximum value in ")
00382 + QString("holder ") + getName() + QString(".");
00383 setLastError(str);
00384 if(qvApp->isRunning()) {
00385 std::cerr << qPrintable("Warning: " + str + "\n");
00386 }
00387 if(ok != NULL) *ok = FALSE;
00388 }
00389 else
00390 if(ok != NULL) *ok = TRUE;
00391 return maximum[name].value<Type>();
00392 }
00393
00400 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00401 {
00402 if(not checkExists(name,"QVPropertyContainer::getPropertyMinimum()"))
00403 if(ok != NULL) *ok = FALSE;
00404 else if(not maximum.contains(name) and not minimum.contains(name))
00405 {
00406 QString str = QString("QVPropertyContainer::getPropertyMinimum():")
00407 + QString(" property ") + name
00408 + QString(" has no minimum value in ")
00409 + QString("holder ") + getName() + QString(".");
00410 setLastError(str);
00411 if(qvApp->isRunning()) {
00412 std::cerr << qPrintable("Warning: " + str + "\n");
00413 }
00414 if(ok != NULL) *ok = FALSE;
00415 }
00416 else
00417 if(ok != NULL) *ok = TRUE;
00418 return minimum[name].value<Type>();
00419 }
00420
00428 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00429
00435 QString getLastError() const;
00436
00444 const QString infoInputProperties() const;
00445
00464 bool linkProperty(QString sourcePropertyName, QVPropertyContainer *destinyContainer, QString destinyPropertyName, LinkType linkType);
00465
00477 void linkProperty(QVPropertyContainer *container, LinkType linkType = SynchronousLink);
00478
00484 void unlink();
00485
00490 static bool areSynchronized(const QList<QVPropertyContainer> containers);
00491
00492 protected:
00493
00494 template <class Type> bool setPropertyRange2(const QString name, const Type & minimum, const Type & maximum)
00495 {
00496 if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00497 return FALSE;
00498 if(minimum <= getPropertyValue<Type>(name) and
00499 maximum >= getPropertyValue<Type>(name))
00500 {
00501 this->minimum[name] = QVariant::fromValue(minimum);
00502 this->maximum[name] = QVariant::fromValue(maximum);
00503 return TRUE;
00504 } else {
00505 QString str = "QVPropertyContainer::setPropertyRange(): property " +
00506 name + " in holder " + getName() + " has value " +
00507 QString("%1").arg(getPropertyValue<Type>(name)) +
00508 ", which is not valid for the range [" +
00509 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00510 setLastError(str);
00511 if(qvApp->isRunning()) {
00512 std::cerr << qPrintable("Warning: " + str + "\n");
00513 }
00514 return FALSE;
00515 }
00516 }
00517
00525 void readInputProperties();
00526
00537 void writeOutputProperties();
00538
00578 template <class Type> bool parseArgument(const QString parameter, const QString value);
00579
00588 void setLastError(QString str) const;
00589
00594 uint inputPropertyWorker(QString prop)
00595 {
00596 if (inputLinks.contains(prop)) return inputLinks[prop]->qvp_orig->getId();
00597 else return 0;
00598 }
00599
00600 private:
00601 QString name;
00602 uint ident;
00603 mutable QString errorString;
00604 QMap<QString, QVariant> variants,safelyCopiedVariants;
00605 QMap<QString, QVariant> minimum, maximum;
00606 QMap<QString, QString> _info;
00607 QMap<QString, PropertyFlags> io_flags;
00608 QMap<QString, PropertyLinkFlags> link_flags;
00609 QList<QString> insertion_order;
00610
00611 static uint maxIdent;
00612 static uint getNewIdent() { return ++maxIdent; }
00613
00614 QReadWriteLock RWLock;
00615 class QVPropertyContainerLink {
00616 public:
00617 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) {
00618
00619 SyncSemaphoreIn.release();
00620
00621 };
00622 QVPropertyContainer *qvp_orig;
00623 QString prop_orig;
00624 QVPropertyContainer *qvp_dest;
00625 QString prop_dest;
00626 LinkType link_type;
00627 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00628 bool markedForDeletion;
00629 };
00630 QMap<QString, QVPropertyContainerLink* > inputLinks;
00631 QMap<QString, QList<QVPropertyContainerLink*> > outputLinks;
00632
00633 const QMap<QString, QVPropertyContainerLink* > getInputLinks() const { return inputLinks; }
00634
00635 template <class Type> bool setPropertyFromArguments(QString propertyName)
00636 {
00637 QStringList arguments = qvApp->arguments();
00638
00639 QMutableStringListIterator iterator(arguments);
00640 while (iterator.hasNext())
00641 {
00642 QString argument = iterator.next();
00643
00644
00645
00646 if (argument.contains(QRegExp("^--")))
00647 {
00648 QString propertyContainerName(argument), parameter(argument), value(argument);
00649
00650
00651
00652 if (argument.contains(QRegExp("^--[^=]+:")))
00653 {
00654 propertyContainerName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00655 if(propertyContainerName != getName())
00656 continue;
00657 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00658 }
00659 else
00660 {
00661 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00662 }
00663 if(parameter != propertyName)
00664 continue;
00665
00666 value.remove(QRegExp("^--[^=]*="));
00667 if(parseArgument<Type>(parameter,value))
00668 {
00669 if(not isInput(propertyName))
00670 {
00671 QString str = QString("QVPropertyContainer::setPropertyFromArguments():")
00672 + QString(" property ") + propertyName
00673 + QString(" in holder ") + getName()
00674 + QString(" is not of Input type, and cannot be parsed.");
00675 setLastError(str);
00676
00677 }
00678 qvApp->setArgumentAsUsed(argument);
00679 return TRUE;
00680 }
00681 }
00682 }
00683
00684 return FALSE;
00685 }
00686
00687 bool correctRange(const QString name, const double & value) const;
00688
00689
00690 bool correctRange(const char *name, const int & value) const;
00691 bool correctRange(QString name, const int & value) const;
00692
00693
00694 template <typename T> bool correctRange(const QString parameter, const T & value) {
00695 Q_UNUSED(parameter);
00696 Q_UNUSED(value);
00697 return TRUE;
00698 }
00699
00700 bool checkExists(const QString name, const QString methodname) const;
00701 bool checkIsNewProperty(const QString name, const QString methodname) const;
00702 };
00703
00704 template <class Type> bool QVPropertyContainer::parseArgument(const QString parameter, const QString value)
00705 {
00706 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00707 ": parameter " + parameter +
00708 " has an unknown type to command line parser " +
00709 QString("(trying to parse value %1)").arg(value) ;
00710 return FALSE;
00711 }
00712
00713 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value);
00714
00715 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value);
00716
00717 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value);
00718
00719 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value);
00720
00721 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyFlags)
00722 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyLinkFlags)
00723
00724 #endif