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