src/qvcore/qvpropertycontainer.h

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
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                         //qDebug() << "PEO adding property" << name << "to container" << getName();
00256                         if(not checkIsNewProperty(name,"QVPropertyContainer::addProperty()"))
00257                                 return FALSE;
00258                         insertion_order.push_back(name);
00259                         //qDebug() << "PEO insertion_order after new property " << name << "->" << insertion_order;
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                                 } // Otherwise, qApp will show the error and won't start the program.
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                                 } // Otherwise, qApp will show the error and won't start the program.
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                                         } // Otherwise, qApp will show the error and won't start the program.
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                                 // SyncSemaphoreIn value must initially be 1:
00619                                 SyncSemaphoreIn.release();
00620                                 // SyncSemaphoreOut is simply initialized with 0 (default value).
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                                 // Only if the name of the property holder is the same as defined in
00644                                 // the argument, in the form --name:property=value, (with name:
00645                                 // optional) the value will be intended to be applied to the property:
00646                                 if (argument.contains(QRegExp("^--")))
00647                                         {
00648                                         QString propertyContainerName(argument), parameter(argument), value(argument);
00649                                         // Checks whether in the argument string there is a name for
00650                                         // restricting the application of the value to a variable of
00651                                         // a specific property holder.
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                                         // If we get here, then we must assign the value to the property:
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                                                         //qApp will show the error and won't start the program.
00677                                                         }
00678                                                 qvApp->setArgumentAsUsed(argument);
00679                                                 return TRUE;
00680                                                 }
00681                                         }
00682                                 }
00683                                 // If we get here, then we did not parse any value for the property:
00684                                 return FALSE;
00685                         }
00686 
00687                 bool correctRange(const QString name, const double & value) const;
00688                 // Any type inference ambiguity resolved with this:
00689                 // 1. For int values:
00690                 bool correctRange(const char *name, const int & value) const;
00691                 bool correctRange(QString name, const int & value) const;
00692 
00693                 // 2. Rest of types have no range, so we always return true:
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

Generated on Thu Jul 17 17:23:27 2008 for QVision by  doxygen 1.5.3