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 #ifndef DOXYGEN_IGNORE_THIS
00041
00050 class QVPropertyContainerInformer : public QObject
00051 {
00052 Q_OBJECT
00053 public:
00057 void emitChange(QVPropertyContainerChange change) {
00058 emit changed(change);
00059 }
00060 signals:
00064 void changed(QVPropertyContainerChange change);
00065 };
00066
00067 #endif
00068
00083 class QVPropertyContainer
00084 {
00085
00086 public:
00128 typedef enum {AsynchronousLink,SynchronousLink,SequentialLink} LinkType;
00129
00134 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2, guiInvisible=0x4, internalProp=0x8} PropertyFlag;
00135 Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
00136
00137 #ifndef DOXYGEN_IGNORE_THIS
00138 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00139 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00140 #endif
00141
00145 QVPropertyContainer(const QString name = QString());
00146
00150 QVPropertyContainer(const QVPropertyContainer &cont);
00151
00155 QVPropertyContainer & operator=(const QVPropertyContainer &cont);
00156
00162 virtual ~QVPropertyContainer();
00163
00167 void setName(const QString name);
00168
00171 const QString getName() const;
00172
00175 uint getId() const;
00176
00182 bool operator==(const QVPropertyContainer &cont) const;
00183
00189 QList<QString> getPropertyList() const;
00190
00197 template <class Type> QList<QString> getPropertyListByType() const
00198 {
00199 QList<QString> result;
00200 QList<QString> names = variants.keys();
00201
00202 for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00203 if(isType<Type>(*i))
00204 result.append(*i);
00205
00206 return result;
00207 }
00208
00217 template <class Type> bool isType(QString name,bool *ok = NULL) const
00218 {
00219 if(not checkExists(name,"QVPropertyContainer::propertyIsType()"))
00220 {
00221 if(ok != NULL) *ok = FALSE;
00222 return FALSE;
00223 }
00224 if(ok != NULL) *ok = TRUE;
00225 QVariant::Type type = QVariant::fromValue(Type()).type();
00226 if ((type != QVariant::UserType) && (variants[name].type() == type))
00227 return TRUE;
00228 if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00229 return TRUE;
00230 return FALSE;
00231 }
00232
00237 bool containsProperty(const QString name) const;
00238
00246 int getPropertyType(const QString name, bool *ok = NULL) const;
00247
00255 template <class Type> bool addProperty(const QString name,
00256 const PropertyFlags flags = inputFlag,
00257 const Type & value = Type(), const QString info = QString("(Info not available)"))
00258 {
00259 if (addPropertyFromQVariant(name, flags, QVariant::fromValue(value), info))
00260 setPropertyFromArguments<Type>(name);
00261 else
00262 return FALSE;
00263
00264 return TRUE;
00265 }
00266
00276 template <class Type> bool addProperty(const QString name,
00277 const PropertyFlags flags,
00278 const Type & value, const QString info,
00279 const Type & minValue, const Type & maxValue)
00280 {
00281 if (addProperty<Type>(name, flags, value, info))
00282 setPropertyRange<Type>(name, minValue, maxValue);
00283 else
00284 return FALSE;
00285
00286 return TRUE;
00287 }
00288
00296 bool addPropertyFromQVariant(const QString &name, const PropertyFlags flags, QVariant variant, const QString info)
00297 {
00298
00299 if(not checkIsNewProperty(name,"QVPropertyContainer::addProperty()"))
00300 return FALSE;
00301 insertion_order.push_back(name);
00302
00303 _info[name] = info;
00304 io_flags[name] = flags;
00305 link_flags[name] = noLinkFlag;
00306
00307 variants[name] = variant;
00308
00309 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::PropertyAdd, name));
00310 return TRUE;
00311 }
00312
00317 bool removeProperty(const QString name);
00318
00319
00320
00321
00323
00324
00329 bool hasRange(const QString name) const;
00330
00335 PropertyFlags getPropertyFlags(const QString name) const { return io_flags[name]; }
00336
00341 bool isInput(const QString name) const;
00342
00347 bool isOutput(const QString name) const;
00348
00353 bool isGUIInvisible(const QString name) const;
00354
00359 bool isLinkedInput(const QString name) const;
00360
00365 bool isLinkedOutput(const QString name) const;
00366
00377 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00378 {
00379 if(not checkExists(name,"QVPropertyContainer::setPropertyValue()"))
00380 return FALSE;
00381 else if (not correctRange(name,value))
00382 return FALSE;
00383 else {
00384 QVariant variant = QVariant::fromValue<Type>(value);
00385 variants[name] = variant;
00386
00387 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::PropertyValue, name, variant));
00388 return TRUE;
00389 }
00390 }
00391
00398 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00399 {
00400 if (not checkExists(name,"QVPropertyContainer::getPropertyValue()")) {
00401 if(ok != NULL) *ok = FALSE;
00402 } else {
00403 if(ok != NULL) *ok = TRUE;
00404 }
00405 return variants[name].value<Type>();
00406 }
00407
00414 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00415
00422 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00423 {
00424 if(not checkExists(name,"QVPropertyContainer::getPropertyMaximum()")) {
00425 if(ok != NULL) *ok = FALSE;
00426 } else if(not maximum.contains(name) and not minimum.contains(name))
00427 {
00428 QString str = QString("QVPropertyContainer::getPropertyMaximum():")
00429 + QString(" property ") + name
00430 + QString(" has no maximum value in ")
00431 + QString("holder ") + getName() + QString(".");
00432 setLastError(str);
00433 if(qvApp->isRunning()) {
00434 std::cerr << qPrintable("Warning: " + str + "\n");
00435 }
00436 if(ok != NULL) *ok = FALSE;
00437 }
00438 else
00439 if(ok != NULL) *ok = TRUE;
00440 return maximum[name].value<Type>();
00441 }
00442
00449 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00450 {
00451 if(not checkExists(name,"QVPropertyContainer::getPropertyMinimum()")) {
00452 if(ok != NULL) *ok = FALSE;
00453 } else if(not maximum.contains(name) and not minimum.contains(name))
00454 {
00455 QString str = QString("QVPropertyContainer::getPropertyMinimum():")
00456 + QString(" property ") + name
00457 + QString(" has no minimum value in ")
00458 + QString("holder ") + getName() + QString(".");
00459 setLastError(str);
00460 if(qvApp->isRunning()) {
00461 std::cerr << qPrintable("Warning: " + str + "\n");
00462 }
00463 if(ok != NULL) *ok = FALSE;
00464 }
00465 else
00466 if(ok != NULL) *ok = TRUE;
00467 return minimum[name].value<Type>();
00468 }
00469
00477 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00478
00484 QString getLastError() const;
00485
00493 const QString infoInputProperties() const;
00494
00513 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer *destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00514 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer &destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00515 virtual bool linkProperty(QVPropertyContainer *destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00516 virtual bool linkProperty(QVPropertyContainer &destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00517 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer *destinyContainer, LinkType linkType = AsynchronousLink);
00518 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer &destinyContainer, LinkType linkType = AsynchronousLink);
00519
00531 virtual void linkProperty(QVPropertyContainer *container, LinkType linkType = AsynchronousLink);
00532 virtual void linkProperty(QVPropertyContainer &container, LinkType linkType = AsynchronousLink);
00533
00548 virtual bool unlinkProperty(QString origName, QVPropertyContainer *destCont, QString destName);
00549 virtual bool unlinkProperty(QString origName, QVPropertyContainer &destCont, QString destName);
00550
00556 virtual void unlink();
00557
00562 static bool areSynchronized(const QList<QVPropertyContainer *> containers);
00563
00569 QVPropertyContainerInformer *getInformer() { return &informer; }
00570
00571
00577
00578
00583 QVPropertyContainer *getSourceContainer(const QString name) const;
00584
00589 QList<QVPropertyContainer *> getDestinyContainers(const QString name) const;
00590
00595 QString getSourceProperty(const QString name) const;
00596
00601 bool isSynchronous(const QString name) const;
00602
00607 bool isSequential(const QString name) const;
00608
00609 #ifndef DOXYGEN_IGNORE_THIS
00610 virtual bool linkUnspecifiedInputProperty(QVPropertyContainer *sourceContainer, QString sourcePropName, LinkType linkType = AsynchronousLink);
00611 virtual bool linkUnspecifiedOutputProperty(QVPropertyContainer *destContainer, QString destPropName, LinkType linkType = AsynchronousLink);
00612 virtual bool treatUnlinkInputProperty(QString destPropName, QVPropertyContainer *sourceCont, QString sourcePropName);
00613 #endif
00614
00615 bool isSequentialGroupMaster() const { return master == this; }
00616 QVPropertyContainer *getMaster() const { return master; }
00617
00618 protected:
00626 void readInputProperties();
00627
00638 void writeOutputProperties();
00639
00679 template <class Type> bool parseArgument(const QString parameter, const QString value);
00680
00689 void setLastError(QString str) const;
00690
00695 uint inputPropertyBlock(QString prop) const
00696 {
00697 if (inputLinks.contains(prop))
00698 return inputLinks[prop]->qvp_orig->getId();
00699 else
00700 return 0;
00701 }
00702
00703
00704 QVPropertyContainerInformer informer;
00705
00706
00707 QList<QList<QVPropertyContainer *> > slavesByLevel;
00708
00709
00710
00711 private:
00712 QString name;
00713 uint ident;
00714 mutable QString errorString;
00715 QMap<QString, QVariant> variants,safelyCopiedVariants;
00716 QMap<QString, QVariant> minimum, maximum;
00717 QMap<QString, QString> _info;
00718 QMap<QString, PropertyFlags> io_flags;
00719 QMap<QString, PropertyLinkFlags> link_flags;
00720 QList<QString> insertion_order;
00721
00722 static uint maxIdent;
00723 static uint getNewIdent() { return ++maxIdent; }
00724
00725
00726 QReadWriteLock RWLock;
00727 class QVPropertyContainerLink {
00728 public:
00729 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_orig_id(_qvp_orig->getId()), qvp_dest(_qvp_dest), prop_dest(_prop_dest), qvp_dest_name(_qvp_dest->getName()), qvp_dest_id(_qvp_dest->getId()), link_type(_link_type), markedForDeletion(FALSE) {
00730
00731 SyncSemaphoreIn.release();
00732
00733 };
00734 QVPropertyContainer *qvp_orig;
00735 QString prop_orig, qvp_orig_name;
00736 uint qvp_orig_id;
00737 QVPropertyContainer *qvp_dest;
00738 QString prop_dest, qvp_dest_name;
00739 uint qvp_dest_id;
00740 LinkType link_type;
00741 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00742 bool markedForDeletion;
00743 };
00744 QMap<QString, QVPropertyContainerLink* > inputLinks;
00745 QMap<QString, QList<QVPropertyContainerLink*> > outputLinks;
00746
00747 const QMap<QString, QVPropertyContainerLink* > getInputLinks() const { return inputLinks; }
00748 void addInputLink(QString prop_dest, QVPropertyContainerLink *link);
00749 void toDeleteLink(QVPropertyContainerLink* link);
00750
00751
00752
00753 QVPropertyContainer *master;
00754 int deepLevel;
00755
00758
00759 bool ProcessPosibleSequentialLink(QVPropertyContainer *destCont);
00760
00761 void updateDeep(int origDeep);
00762
00763 void ProcessSequentialUnlink(QVPropertyContainer *origCont, QVPropertyContainer *destCont);
00764
00765 bool haveSyncPrecursor(QVPropertyContainer *precursor);
00766
00767 void propagateBackwardMasterChange(QVPropertyContainer *newMaster);
00768
00769 void propagateForwardMasterChange(QVPropertyContainer *newMaster);
00770
00771 void changeMaster(QVPropertyContainer *newMaster);
00772
00773 QList<QVPropertyContainer *> getDestinySequentialContainers(const QString name) const;
00776
00777
00778 template <class Type> bool setPropertyRange(const QString name, const Type & minimum, const Type & maximum)
00779 {
00780 if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00781 return FALSE;
00782 if(minimum <= getPropertyValue<Type>(name) and
00783 maximum >= getPropertyValue<Type>(name))
00784 {
00785 this->minimum[name] = QVariant::fromValue(minimum);
00786 this->maximum[name] = QVariant::fromValue(maximum);
00787 return TRUE;
00788 } else {
00789 QString str = "QVPropertyContainer::setPropertyRange(): property " +
00790 name + " in holder " + getName() + " has value " +
00791 QString("%1").arg(getPropertyValue<Type>(name)) +
00792 ", which is not valid for the range [" +
00793 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00794 setLastError(str);
00795 if(qvApp->isRunning()) {
00796 std::cerr << qPrintable("Warning: " + str + "\n");
00797 }
00798 return FALSE;
00799 }
00800 }
00801
00802 template <class Type> bool setPropertyFromArguments(QString propertyName)
00803 {
00804 QStringList arguments = qvApp->arguments();
00805
00806 QMutableStringListIterator iterator(arguments);
00807 while (iterator.hasNext())
00808 {
00809 QString argument = iterator.next();
00810
00811
00812
00813 if (argument.contains(QRegExp("^--")))
00814 {
00815 QString propertyContainerName(argument), parameter(argument), value(argument);
00816
00817
00818
00819 if (argument.contains(QRegExp("^--[^=]+:")))
00820 {
00821 propertyContainerName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00822 if(propertyContainerName != getName())
00823 continue;
00824 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00825 }
00826 else
00827 {
00828 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00829 }
00830 if(parameter != propertyName)
00831 continue;
00832
00833 value.remove(QRegExp("^--[^=]*="));
00834 if(parseArgument<Type>(parameter,value))
00835 {
00836 if(not isInput(propertyName))
00837 {
00838 QString str = QString("QVPropertyContainer::setPropertyFromArguments():")
00839 + QString(" property ") + propertyName
00840 + QString(" in holder ") + getName()
00841 + QString(" is not of Input type, and cannot be parsed.");
00842 setLastError(str);
00843
00844 }
00845 qvApp->setArgumentAsUsed(argument);
00846 return TRUE;
00847 }
00848 }
00849 }
00850
00851 return FALSE;
00852 }
00853
00854 bool correctRange(const QString name, const double & value) const;
00855
00856
00857 bool correctRange(const char *name, const int & value) const;
00858 bool correctRange(QString name, const int & value) const;
00859
00860
00861 template <typename T> bool correctRange(const QString parameter, const T & value) {
00862 Q_UNUSED(parameter);
00863 Q_UNUSED(value);
00864 return TRUE;
00865 }
00866
00867 bool checkExists(const QString name, const QString methodname) const;
00868 bool checkIsNewProperty(const QString name, const QString methodname) const;
00869 };
00870
00871 template <class Type> bool QVPropertyContainer::parseArgument(const QString parameter, const QString value)
00872 {
00873
00874 bool ok,ok2;
00875 ok2 = isType<float>(parameter,&ok);
00876 if(ok and ok2)
00877 return parseArgument<double>(parameter, value);
00878
00879 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00880 ": parameter " + parameter +
00881 " has an unknown type to command line parser " +
00882 QString("(trying to parse value %1)").arg(value) ;
00883 return FALSE;
00884 }
00885
00886 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value);
00887 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value);
00888 template <> bool QVPropertyContainer::parseArgument<float>(const QString parameter, const QString value);
00889 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value);
00890 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value);
00891
00892 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyFlags)
00893 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyLinkFlags)
00894
00895 #endif