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
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
00081 class QVPropertyContainer
00082 {
00083
00084 public:
00126 typedef enum {AsynchronousLink,SynchronousLink,SequentialLink} LinkType;
00127
00132 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2, guiInvisible=0x4, internalProp=0x8} PropertyFlag;
00133 Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
00134
00135 #ifndef DOXYGEN_IGNORE_THIS
00136 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00137 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00138 #endif
00139
00143 QVPropertyContainer(const QString name = QString());
00144
00148 QVPropertyContainer(const QVPropertyContainer &cont);
00149
00153 QVPropertyContainer & operator=(const QVPropertyContainer &cont);
00154
00160 virtual ~QVPropertyContainer();
00161
00165 void setName(const QString name);
00166
00169 const QString getName() const;
00170
00173 const uint getId() const;
00174
00180 bool operator==(const QVPropertyContainer &cont) const;
00181
00187 QList<QString> getPropertyList() const;
00188
00195 template <class Type> QList<QString> getPropertyListByType() const
00196 {
00197 QList<QString> result;
00198 QList<QString> names = variants.keys();
00199
00200 for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00201 if(isType<Type>(*i))
00202 result.append(*i);
00203
00204 return result;
00205 }
00206
00215 template <class Type> bool isType(QString name,bool *ok = NULL) const
00216 {
00217 if(not checkExists(name,"QVPropertyContainer::propertyIsType()"))
00218 {
00219 if(ok != NULL) *ok = FALSE;
00220 return FALSE;
00221 }
00222 if(ok != NULL) *ok = TRUE;
00223 QVariant::Type type = QVariant::fromValue(Type()).type();
00224 if ((type != QVariant::UserType) && (variants[name].type() == type))
00225 return TRUE;
00226 if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00227 return TRUE;
00228 return FALSE;
00229 }
00230
00235 bool containsProperty(const QString name) const;
00236
00244 int getPropertyType(const QString name, bool *ok = NULL) const;
00245
00253 template <class Type> bool addProperty(const QString name,
00254 const PropertyFlags flags = inputFlag,
00255 const Type & value = Type(), const QString info = QString("(Info not available)"))
00256 {
00257 if (addPropertyFromQVariant(name, flags, QVariant::fromValue(value), info))
00258 setPropertyFromArguments<Type>(name);
00259 else
00260 return FALSE;
00261
00262 return TRUE;
00263 }
00264
00274 template <class Type> bool addProperty(const QString name,
00275 const PropertyFlags flags,
00276 const Type & value, const QString info,
00277 const Type & minValue, const Type & maxValue)
00278 {
00279 if (addProperty<Type>(name, flags, value, info))
00280 setPropertyRange<Type>(name, minValue, maxValue);
00281 else
00282 return FALSE;
00283
00284 return TRUE;
00285 }
00286
00294 bool addPropertyFromQVariant(const QString &name, const PropertyFlags flags, QVariant variant, const QString info)
00295 {
00296
00297 if(not checkIsNewProperty(name,"QVPropertyContainer::addProperty()"))
00298 return FALSE;
00299 insertion_order.push_back(name);
00300
00301 _info[name] = info;
00302 io_flags[name] = flags;
00303 link_flags[name] = noLinkFlag;
00304
00305 variants[name] = variant;
00306
00307 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::PropertyAdd, name));
00308 return TRUE;
00309 }
00310
00315 bool removeProperty(const QString name);
00316
00317
00318
00319
00321
00322
00327 bool hasRange(const QString name) const;
00328
00333 PropertyFlags getPropertyFlags(const QString name) const { return io_flags[name]; }
00334
00339 bool isInput(const QString name) const;
00340
00345 bool isOutput(const QString name) const;
00346
00351 bool isGUIInvisible(const QString name) const;
00352
00357 bool isLinkedInput(const QString name) const;
00358
00363 bool isLinkedOutput(const QString name) const;
00364
00375 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00376 {
00377 if(not checkExists(name,"QVPropertyContainer::setPropertyValue()"))
00378 return FALSE;
00379 else if (not correctRange(name,value))
00380 return FALSE;
00381 else {
00382 QVariant variant = QVariant::fromValue<Type>(value);
00383 variants[name] = variant;
00384
00385 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::PropertyValue, name, variant));
00386 return TRUE;
00387 }
00388 }
00389
00396 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00397 {
00398 if (not checkExists(name,"QVPropertyContainer::getPropertyValue()"))
00399 if(ok != NULL) *ok = FALSE;
00400 else
00401 if(ok != NULL) *ok = TRUE;
00402 return variants[name].value<Type>();
00403 }
00404
00411 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00412
00419 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00420 {
00421 if(not checkExists(name,"QVPropertyContainer::getPropertyMaximum()"))
00422 if(ok != NULL) *ok = FALSE;
00423 else if(not maximum.contains(name) and not minimum.contains(name))
00424 {
00425 QString str = QString("QVPropertyContainer::getPropertyMaximum():")
00426 + QString(" property ") + name
00427 + QString(" has no maximum value in ")
00428 + QString("holder ") + getName() + QString(".");
00429 setLastError(str);
00430 if(qvApp->isRunning()) {
00431 std::cerr << qPrintable("Warning: " + str + "\n");
00432 }
00433 if(ok != NULL) *ok = FALSE;
00434 }
00435 else
00436 if(ok != NULL) *ok = TRUE;
00437 return maximum[name].value<Type>();
00438 }
00439
00446 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00447 {
00448 if(not checkExists(name,"QVPropertyContainer::getPropertyMinimum()"))
00449 if(ok != NULL) *ok = FALSE;
00450 else if(not maximum.contains(name) and not minimum.contains(name))
00451 {
00452 QString str = QString("QVPropertyContainer::getPropertyMinimum():")
00453 + QString(" property ") + name
00454 + QString(" has no minimum value in ")
00455 + QString("holder ") + getName() + QString(".");
00456 setLastError(str);
00457 if(qvApp->isRunning()) {
00458 std::cerr << qPrintable("Warning: " + str + "\n");
00459 }
00460 if(ok != NULL) *ok = FALSE;
00461 }
00462 else
00463 if(ok != NULL) *ok = TRUE;
00464 return minimum[name].value<Type>();
00465 }
00466
00474 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00475
00481 QString getLastError() const;
00482
00490 const QString infoInputProperties() const;
00491
00510 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer *destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00511 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer &destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00512 virtual bool linkProperty(QVPropertyContainer *destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00513 virtual bool linkProperty(QVPropertyContainer &destinyContainer, QString destinyPropName, LinkType linkType = AsynchronousLink);
00514 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer *destinyContainer, LinkType linkType = AsynchronousLink);
00515 virtual bool linkProperty(QString sourcePropName, QVPropertyContainer &destinyContainer, LinkType linkType = AsynchronousLink);
00516
00528 virtual void linkProperty(QVPropertyContainer *container, LinkType linkType = AsynchronousLink);
00529 virtual void linkProperty(QVPropertyContainer &container, LinkType linkType = AsynchronousLink);
00530
00545 virtual bool unlinkProperty(QString origName, QVPropertyContainer *destCont, QString destName);
00546 virtual bool unlinkProperty(QString origName, QVPropertyContainer &destCont, QString destName);
00547
00553 virtual void unlink();
00554
00559 static bool areSynchronized(const QList<QVPropertyContainer *> containers);
00560
00566 QVPropertyContainerInformer *getInformer() { return &informer; }
00567
00568
00574
00575
00580 QVPropertyContainer *getSourceContainer(const QString name) const;
00581
00586 QList<QVPropertyContainer *> getDestinyContainers(const QString name) const;
00587
00592 QString getSourceProperty(const QString name) const;
00593
00598 bool isSynchronous(const QString name) const;
00599
00604 bool isSequential(const QString name) const;
00605
00606 #ifndef DOXYGEN_IGNORE_THIS
00607 virtual bool linkUnspecifiedInputProperty(QVPropertyContainer *sourceContainer, QString sourcePropName, LinkType linkType = AsynchronousLink);
00608 virtual bool linkUnspecifiedOutputProperty(QVPropertyContainer *destContainer, QString destPropName, LinkType linkType = AsynchronousLink);
00609 virtual bool treatUnlinkInputProperty(QString destPropName, QVPropertyContainer *sourceCont, QString sourcePropName);
00610 #endif
00611
00612 const bool isSequentialGroupMaster() const { return master == this; }
00613 QVPropertyContainer *getMaster() const { return master; }
00614
00615 protected:
00623 void readInputProperties();
00624
00635 void writeOutputProperties();
00636
00676 template <class Type> bool parseArgument(const QString parameter, const QString value);
00677
00686 void setLastError(QString str) const;
00687
00692 uint inputPropertyWorker(QString prop) const
00693 {
00694 if (inputLinks.contains(prop))
00695 return inputLinks[prop]->qvp_orig->getId();
00696 else
00697 return 0;
00698 }
00699
00700
00701 QVPropertyContainerInformer informer;
00702
00703
00704 QList<QList<QVPropertyContainer *> > slavesByLevel;
00705
00706
00707
00708 private:
00709 QString name;
00710 uint ident;
00711 mutable QString errorString;
00712 QMap<QString, QVariant> variants,safelyCopiedVariants;
00713 QMap<QString, QVariant> minimum, maximum;
00714 QMap<QString, QString> _info;
00715 QMap<QString, PropertyFlags> io_flags;
00716 QMap<QString, PropertyLinkFlags> link_flags;
00717 QList<QString> insertion_order;
00718
00719 static uint maxIdent;
00720 static uint getNewIdent() { return ++maxIdent; }
00721
00722
00723 QReadWriteLock RWLock;
00724 class QVPropertyContainerLink {
00725 public:
00726 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) {
00727
00728 SyncSemaphoreIn.release();
00729
00730 };
00731 QVPropertyContainer *qvp_orig;
00732 QString prop_orig, qvp_orig_name;
00733 uint qvp_orig_id;
00734 QVPropertyContainer *qvp_dest;
00735 QString prop_dest, qvp_dest_name;
00736 uint qvp_dest_id;
00737 LinkType link_type;
00738 QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00739 bool markedForDeletion;
00740 };
00741 QMap<QString, QVPropertyContainerLink* > inputLinks;
00742 QMap<QString, QList<QVPropertyContainerLink*> > outputLinks;
00743
00744 const QMap<QString, QVPropertyContainerLink* > getInputLinks() const { return inputLinks; }
00745 void addInputLink(QString prop_dest, QVPropertyContainerLink *link);
00746 void toDeleteLink(QVPropertyContainerLink* link);
00747
00748
00749
00750 QVPropertyContainer *master;
00751 int deepLevel;
00752
00755
00756 bool ProcessPosibleSequentialLink(QVPropertyContainer *destCont);
00757
00758 void updateDeep(int origDeep);
00759
00760 void ProcessSequentialUnlink(QVPropertyContainer *origCont, QVPropertyContainer *destCont);
00761
00762 bool haveSyncPrecursor(QVPropertyContainer *precursor);
00763
00764 void propagateBackwardMasterChange(QVPropertyContainer *newMaster);
00765
00766 void propagateForwardMasterChange(QVPropertyContainer *newMaster);
00767
00768 void changeMaster(QVPropertyContainer *newMaster);
00769
00770 QList<QVPropertyContainer *> getDestinySequentialContainers(const QString name) const;
00773
00774
00775 template <class Type> bool setPropertyRange(const QString name, const Type & minimum, const Type & maximum)
00776 {
00777 if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00778 return FALSE;
00779 if(minimum <= getPropertyValue<Type>(name) and
00780 maximum >= getPropertyValue<Type>(name))
00781 {
00782 this->minimum[name] = QVariant::fromValue(minimum);
00783 this->maximum[name] = QVariant::fromValue(maximum);
00784 return TRUE;
00785 } else {
00786 QString str = "QVPropertyContainer::setPropertyRange(): property " +
00787 name + " in holder " + getName() + " has value " +
00788 QString("%1").arg(getPropertyValue<Type>(name)) +
00789 ", which is not valid for the range [" +
00790 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00791 setLastError(str);
00792 if(qvApp->isRunning()) {
00793 std::cerr << qPrintable("Warning: " + str + "\n");
00794 }
00795 return FALSE;
00796 }
00797 }
00798
00799 template <class Type> bool setPropertyFromArguments(QString propertyName)
00800 {
00801 QStringList arguments = qvApp->arguments();
00802
00803 QMutableStringListIterator iterator(arguments);
00804 while (iterator.hasNext())
00805 {
00806 QString argument = iterator.next();
00807
00808
00809
00810 if (argument.contains(QRegExp("^--")))
00811 {
00812 QString propertyContainerName(argument), parameter(argument), value(argument);
00813
00814
00815
00816 if (argument.contains(QRegExp("^--[^=]+:")))
00817 {
00818 propertyContainerName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00819 if(propertyContainerName != getName())
00820 continue;
00821 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00822 }
00823 else
00824 {
00825 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00826 }
00827 if(parameter != propertyName)
00828 continue;
00829
00830 value.remove(QRegExp("^--[^=]*="));
00831 if(parseArgument<Type>(parameter,value))
00832 {
00833 if(not isInput(propertyName))
00834 {
00835 QString str = QString("QVPropertyContainer::setPropertyFromArguments():")
00836 + QString(" property ") + propertyName
00837 + QString(" in holder ") + getName()
00838 + QString(" is not of Input type, and cannot be parsed.");
00839 setLastError(str);
00840
00841 }
00842 qvApp->setArgumentAsUsed(argument);
00843 return TRUE;
00844 }
00845 }
00846 }
00847
00848 return FALSE;
00849 }
00850
00851 bool correctRange(const QString name, const double & value) const;
00852
00853
00854 bool correctRange(const char *name, const int & value) const;
00855 bool correctRange(QString name, const int & value) const;
00856
00857
00858 template <typename T> bool correctRange(const QString parameter, const T & value) {
00859 Q_UNUSED(parameter);
00860 Q_UNUSED(value);
00861 return TRUE;
00862 }
00863
00864 bool checkExists(const QString name, const QString methodname) const;
00865 bool checkIsNewProperty(const QString name, const QString methodname) const;
00866 };
00867
00868 template <class Type> bool QVPropertyContainer::parseArgument(const QString parameter, const QString value)
00869 {
00870 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00871 ": parameter " + parameter +
00872 " has an unknown type to command line parser " +
00873 QString("(trying to parse value %1)").arg(value) ;
00874 return FALSE;
00875 }
00876
00877 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value);
00878
00879 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value);
00880
00881 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value);
00882
00883 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value);
00884
00885 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyFlags)
00886 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyContainer::PropertyLinkFlags)
00887
00888 #endif