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 #include <QVPropertyContainerChange>
00036
00037 #include <iostream>
00038 #include <QVApplication>
00039
00040
00049 class QVPropertyContainerInformer : public QObject
00050 {
00051 Q_OBJECT
00052 public:
00056 void emitChange(QVPropertyContainerChange change) {
00057 emit changed(change);
00058 }
00059 signals:
00063 void changed(QVPropertyContainerChange change);
00064 };
00065
00066
00067
00082 class QVPropertyContainer
00083 {
00084
00085 public:
00118 typedef enum {AsynchronousLink,SynchronousLink} LinkType;
00119
00124 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2, guiInvisible=0x4, internalProp=0x8} PropertyFlag;
00125 Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
00126
00127 #ifndef DOXYGEN_IGNORE_THIS
00128 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00129 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00130 #endif
00131
00135 QVPropertyContainer(const QString name = QString());
00136
00140 QVPropertyContainer(const QVPropertyContainer &cont);
00141
00145 QVPropertyContainer & operator=(const QVPropertyContainer &cont);
00146
00152 virtual ~QVPropertyContainer();
00153
00157 void setName(const QString name);
00158
00161 const QString getName() const;
00162
00165 const uint getId() const;
00166
00172 bool operator==(const QVPropertyContainer &cont) const;
00173
00179 QList<QString> getPropertyList() const;
00180
00187 template <class Type> QList<QString> getPropertyListByType() const
00188 {
00189 QList<QString> result;
00190 QList<QString> names = variants.keys();
00191
00192 for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00193 if(isType<Type>(*i))
00194 result.append(*i);
00195
00196 return result;
00197 }
00198
00207 template <class Type> bool isType(QString name,bool *ok = NULL) const
00208 {
00209 if(not checkExists(name,"QVPropertyContainer::propertyIsType()"))
00210 {
00211 if(ok != NULL) *ok = FALSE;
00212 return FALSE;
00213 }
00214 if(ok != NULL) *ok = TRUE;
00215 QVariant::Type type = QVariant::fromValue(Type()).type();
00216 if ((type != QVariant::UserType) && (variants[name].type() == type))
00217 return TRUE;
00218 if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00219 return TRUE;
00220 return FALSE;
00221 }
00222
00227 bool containsProperty(const QString name) const;
00228
00236 int getPropertyType(const QString name, bool *ok = NULL) const;
00237
00245 template <class Type> bool addProperty(const QString name,
00246 const PropertyFlags flags = inputFlag,
00247 const Type & value = Type(), const QString info = QString("(Info not available)"))
00248 {
00249 if (addPropertyFromQVariant(name, flags, QVariant::fromValue(value), info))
00250 setPropertyFromArguments<Type>(name);
00251 else
00252 return FALSE;
00253
00254 return TRUE;
00255 }
00256
00266 template <class Type> bool addProperty(const QString name,
00267 const PropertyFlags flags,
00268 const Type & value, const QString info,
00269 const Type & minValue, const Type & maxValue)
00270 {
00271 if (addProperty<Type>(name, flags, value, info))
00272 setPropertyRange<Type>(name, minValue, maxValue);
00273 else
00274 return FALSE;
00275
00276 return TRUE;
00277 }
00278
00286 bool addPropertyFromQVariant(const QString &name, const PropertyFlags flags, QVariant variant, const QString info)
00287 {
00288
00289 if(not checkIsNewProperty(name,"QVPropertyContainer::addProperty()"))
00290 return FALSE;
00291 insertion_order.push_back(name);
00292
00293 _info[name] = info;
00294 io_flags[name] = flags;
00295 link_flags[name] = noLinkFlag;
00296
00297 variants[name] = variant;
00298
00299 informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::PropertyAdd, name));
00300 return TRUE;
00301 }
00302
00307 bool removeProperty(const QString name);
00308
00309
00310
00311
00313
00314
00319 bool hasRange(const QString name) const;
00320
00325 PropertyFlags getPropertyFlags(const QString name) const { return io_flags[name]; }
00326
00331 bool isInput(const QString name) const;
00332
00337 bool isOutput(const QString name) const;
00338
00343 bool isGUIInvisible(const QString name) const;
00344
00349 bool isLinkedInput(const QString name) const;
00350
00355 bool isLinkedOutput(const QString name) const;
00356
00367 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00368 {
00369 if(not checkExists(name,"QVPropertyContainer::setPropertyValue()"))
00370 return FALSE;
00371 else if (not correctRange(name,value))
00372 return FALSE;
00373 else {
00374 QVariant variant = QVariant::fromValue<Type>(value);
00375 variants[name] = variant;
00376
00377 informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::PropertyValue, name, variant));
00378 return TRUE;
00379 }
00380 }
00381
00388 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00389 {
00390 if (not checkExists(name,"QVPropertyContainer::getPropertyValue()"))
00391 if(ok != NULL) *ok = FALSE;
00392 else
00393 if(ok != NULL) *ok = TRUE;
00394 return variants[name].value<Type>();
00395 }
00396
00403 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00404
00411 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00412 {
00413 if(not checkExists(name,"QVPropertyContainer::getPropertyMaximum()"))
00414 if(ok != NULL) *ok = FALSE;
00415 else if(not maximum.contains(name) and not minimum.contains(name))
00416 {
00417 QString str = QString("QVPropertyContainer::getPropertyMaximum():")
00418 + QString(" property ") + name
00419 + QString(" has no maximum value in ")
00420 + QString("holder ") + getName() + QString(".");
00421 setLastError(str);
00422 if(qvApp->isRunning()) {
00423 std::cerr << qPrintable("Warning: " + str + "\n");
00424 }
00425 if(ok != NULL) *ok = FALSE;
00426 }
00427 else
00428 if(ok != NULL) *ok = TRUE;
00429 return maximum[name].value<Type>();
00430 }
00431
00438 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00439 {
00440 if(not checkExists(name,"QVPropertyContainer::getPropertyMinimum()"))
00441 if(ok != NULL) *ok = FALSE;
00442 else if(not maximum.contains(name) and not minimum.contains(name))
00443 {
00444 QString str = QString("QVPropertyContainer::getPropertyMinimum():")
00445 + QString(" property ") + name
00446 + QString(" has no minimum value in ")
00447 + QString("holder ") + getName() + QString(".");
00448 setLastError(str);
00449 if(qvApp->isRunning()) {
00450 std::cerr << qPrintable("Warning: " + str + "\n");
00451 }
00452 if(ok != NULL) *ok = FALSE;
00453 }
00454 else
00455 if(ok != NULL) *ok = TRUE;
00456 return minimum[name].value<Type>();
00457 }
00458
00466 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00467
00473 QString getLastError() const;
00474
00482 const QString infoInputProperties() const;
00483
00502 bool linkProperty(QString sourcePropertyName, QVPropertyContainer *destinyContainer, QString destinyPropertyName, LinkType linkType);
00503
00515 void linkProperty(QVPropertyContainer *container, LinkType linkType = SynchronousLink);
00516
00531 bool unlinkProperty(QString origName, QVPropertyContainer *destCont, QString destName);
00532
00538 void unlink();
00539
00544 static bool areSynchronized(const QList<QVPropertyContainer *> containers);
00545
00551 QVPropertyContainerInformer *getInformer() { return &informer; }
00552
00553
00559
00560
00565 QVPropertyContainer *getSourceContainer(const QString name) const;
00566
00571 QString getSourceProperty(const QString name) const;
00572
00577 bool isSynchronous(const QString name) const;
00578
00579 protected:
00587 void readInputProperties();
00588
00599 void writeOutputProperties();
00600
00640 template <class Type> bool parseArgument(const QString parameter, const QString value);
00641
00650 void setLastError(QString str) const;
00651
00656 uint inputPropertyWorker(QString prop) const
00657 {
00658 if (inputLinks.contains(prop)) return inputLinks[prop]->qvp_orig->getId();
00659 else return 0;
00660 }
00661
00662 private:
00663 QString name;
00664 uint ident;
00665 mutable QString errorString;
00666 QMap<QString, QVariant> variants,safelyCopiedVariants;
00667 QMap<QString, QVariant> minimum, maximum;
00668 QMap<QString, QString> _info;
00669 QMap<QString, PropertyFlags> io_flags;
00670 QMap<QString, PropertyLinkFlags> link_flags;
00671 QList<QString> insertion_order;
00672 QVPropertyContainerInformer informer;
00673
00674 static uint maxIdent;
00675 static uint getNewIdent() { return ++maxIdent; }
00676
00677
00678 QReadWriteLock RWLock;
00679 class QVPropertyContainerLink {
00680 public:
00681 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_orig_name(_qvp_orig->getName()), qvp_dest(_qvp_dest), prop_dest(_prop_dest), qvp_dest_name(_qvp_dest->getName()), link_type(_link_type), markedForDeletion(FALSE) {
00682
00683 SyncSemaphoreIn.release();
00684
00685 };
00686 QVPropertyContainer *qvp_orig;
00687 QString prop_orig, qvp_orig_name;
00688 QVPropertyContainer *qvp_dest;
00689 QString prop_dest, qvp_dest_name;
00690 LinkType link_type;
00691 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00692 bool markedForDeletion;
00693 };
00694 QMap<QString, QVPropertyContainerLink* > inputLinks;
00695 QMap<QString, QList<QVPropertyContainerLink*> > outputLinks;
00696
00697 const QMap<QString, QVPropertyContainerLink* > getInputLinks() const { return inputLinks; }
00698 void addInputLink(QString prop_dest, QVPropertyContainerLink *link);
00699 void toDeleteLink(QVPropertyContainerLink* link);
00700
00701 template <class Type> bool setPropertyRange(const QString name, const Type & minimum, const Type & maximum)
00702 {
00703 if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00704 return FALSE;
00705 if(minimum <= getPropertyValue<Type>(name) and
00706 maximum >= getPropertyValue<Type>(name))
00707 {
00708 this->minimum[name] = QVariant::fromValue(minimum);
00709 this->maximum[name] = QVariant::fromValue(maximum);
00710 return TRUE;
00711 } else {
00712 QString str = "QVPropertyContainer::setPropertyRange(): property " +
00713 name + " in holder " + getName() + " has value " +
00714 QString("%1").arg(getPropertyValue<Type>(name)) +
00715 ", which is not valid for the range [" +
00716 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00717 setLastError(str);
00718 if(qvApp->isRunning()) {
00719 std::cerr << qPrintable("Warning: " + str + "\n");
00720 }
00721 return FALSE;
00722 }
00723 }
00724
00725 template <class Type> bool setPropertyFromArguments(QString propertyName)
00726 {
00727 QStringList arguments = qvApp->arguments();
00728
00729 QMutableStringListIterator iterator(arguments);
00730 while (iterator.hasNext())
00731 {
00732 QString argument = iterator.next();
00733
00734
00735
00736 if (argument.contains(QRegExp("^--")))
00737 {
00738 QString propertyContainerName(argument), parameter(argument), value(argument);
00739
00740
00741
00742 if (argument.contains(QRegExp("^--[^=]+:")))
00743 {
00744 propertyContainerName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00745 if(propertyContainerName != getName())
00746 continue;
00747 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00748 }
00749 else
00750 {
00751 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00752 }
00753 if(parameter != propertyName)
00754 continue;
00755
00756 value.remove(QRegExp("^--[^=]*="));
00757 if(parseArgument<Type>(parameter,value))
00758 {
00759 if(not isInput(propertyName))
00760 {
00761 QString str = QString("QVPropertyContainer::setPropertyFromArguments():")
00762 + QString(" property ") + propertyName
00763 + QString(" in holder ") + getName()
00764 + QString(" is not of Input type, and cannot be parsed.");
00765 setLastError(str);
00766
00767 }
00768 qvApp->setArgumentAsUsed(argument);
00769 return TRUE;
00770 }
00771 }
00772 }
00773
00774 return FALSE;
00775 }
00776
00777 bool correctRange(const QString name, const double & value) const;
00778
00779
00780 bool correctRange(const char *name, const int & value) const;
00781 bool correctRange(QString name, const int & value) const;
00782
00783
00784 template <typename T> bool correctRange(const QString parameter, const T & value) {
00785 Q_UNUSED(parameter);
00786 Q_UNUSED(value);
00787 return TRUE;
00788 }
00789
00790 bool checkExists(const QString name, const QString methodname) const;
00791 bool checkIsNewProperty(const QString name, const QString methodname) const;
00792 };
00793
00794 template <class Type> bool QVPropertyContainer::parseArgument(const QString parameter, const QString value)
00795 {
00796 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00797 ": parameter " + parameter +
00798 " has an unknown type to command line parser " +
00799 QString("(trying to parse value %1)").arg(value) ;
00800 return FALSE;
00801 }
00802
00803 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value);
00804
00805 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value);
00806
00807 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value);
00808
00809 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value);
00810
00811 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyFlags)
00812 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyLinkFlags)
00813
00814 #endif