src/qvcore/qvpropertyholder.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 
00040 #define READ_PROPERTY(HOLDER, TYPE, NAME, VARIABLE) TYPE VARIABLE = HOLDER->getPropertyValue<TYPE>(NAME);
00041 #define READ_PROPERTY_MAX(HOLDER, TYPE, NAME, VARIABLE) TYPE VARIABLE = HOLDER->getPropertyMaximum<TYPE>(NAME);
00042 #define READ_PROPERTY_MIN(HOLDER, TYPE, NAME, VARIABLE) TYPE VARIABLE = HOLDER->getPropertyMinimum<TYPE>(NAME);
00043 
00071 class QVPropertyHolder
00072         {
00073         public:
00106                 typedef enum {AsynchronousLink,SynchronousLink} LinkType;
00107 
00112                 typedef enum {noInputOutputFlag=0x0,inputFlag=0x1,outputFlag=0x2} PropertyInputOutputFlag;
00113                 Q_DECLARE_FLAGS(PropertyInputOutputFlags, PropertyInputOutputFlag)
00114 
00115                 
00116                 typedef enum {noLinkFlag=0x0,linkedInputFlag=0x1,linkedOutputFlag=0x2} PropertyLinkFlag;
00117                 Q_DECLARE_FLAGS(PropertyLinkFlags, PropertyLinkFlag)
00119 
00123                 QVPropertyHolder(const QString name = QString());
00124 
00130                 virtual ~QVPropertyHolder();
00131 
00135                 void setName(const QString name);
00136 
00139                 const QString getName() const;
00140 
00146                 QList<QString> getPropertyList() const;
00147 
00154                 template <class Type> QList<QString> getPropertyListByType() const
00155                         {
00156                         QList<QString> result;
00157                         QList<QString> names = variants.keys();
00158 
00159                         for(QList<QString>::iterator i = names.begin();i != names.end();++i)
00160                                 if(isType<Type>(*i))
00161                                         result.append(*i);
00162 
00163                         return result;
00164                         }
00165 
00174                 template <class Type> bool isType(QString name,bool *ok = NULL) const
00175                         {
00176                         if(not checkExists(name,"QVPropertyHolder::propertyIsType()"))
00177                                 {
00178                                 if(ok != NULL) *ok = FALSE;
00179                                 return FALSE;
00180                                 }
00181                         if(ok != NULL) *ok = TRUE;
00182                         QVariant::Type type = QVariant::fromValue(Type()).type();
00183                         if ((type != QVariant::UserType) && (variants[name].type() == type))
00184                                 return TRUE;
00185                         if (variants[name].userType() == QVariant::fromValue(Type()).userType())
00186                                 return TRUE;
00187                         return FALSE;
00188                         }
00189 
00194                 bool containsProperty(const QString name) const;
00195 
00204                 QVariant::Type getPropertyType(const QString name, bool *ok = NULL) const;
00205 
00213                 template <class Type> bool addProperty(const QString name,
00214                         const PropertyInputOutputFlags flags = inputFlag,
00215                         const Type & value = Type(), const QString info = QString("(Info not available)"))
00216                         {
00217                         if(not checkIsNewProperty(name,"QVPropertyHolder::addProperty()"))
00218                                 return FALSE;
00219                         insertion_order.push_back(name);
00220                         _info[name] = info;
00221                         io_flags[name] = flags;
00222                         link_flags[name] = noLinkFlag;
00223 
00224                         // If possible, we set the initial value from the command line;
00225                         // otherwise, we let the default:
00226                         variants[name] = QVariant::fromValue(value);
00227                         setPropertyFromArguments<Type>(name);
00228                         return TRUE;
00229                         }
00230 
00240                 template <class Type> bool addProperty(const QString name,
00241                         const PropertyInputOutputFlags flags,
00242                         const Type & value, const QString info,
00243                         const Type & minValue, const Type & maxValue)
00244                         {
00245                         addProperty<Type>(name, flags, value, info);
00246                         setPropertyRange2<Type>(name, minValue, maxValue);
00247                         return TRUE;
00248                         }
00249 
00254                 bool removeProperty(const QString name);
00255 
00267                 bool setPropertyRange(const QString name, const double & minimum, const double & maximum);
00268 
00269                 // Any type inference ambiguity resolved with this:
00272                 bool setPropertyRange(const char *name, int & minimum, int & maximum);
00274                 bool setPropertyRange(QString name, int & minimum, int & maximum);
00276 
00281                 bool hasRange(const QString name);
00282 
00287                 bool isInput(const QString name);
00288 
00293                 bool isOutput(const QString name);
00294 
00299                 bool isLinkedInput(const QString name);
00300 
00305                 bool isLinkedOutput(const QString name);
00306 
00317                 template <class Type> bool setPropertyValue(const QString name, const Type &value)
00318                         {
00319                         if(not checkExists(name,"QVPropertyHolder::setPropertyValue()"))
00320                                 return FALSE;
00321                         else if (not correctRange(name,value))
00322                                 return FALSE;
00323                         else    {
00324                                 variants[name] = QVariant::fromValue<Type>(value);
00325                                 return TRUE;
00326                                 }
00327                         }
00328 
00335                 template <class Type> Type getPropertyValue(const QString name, bool *ok = NULL) const
00336                         {
00337                         if (not checkExists(name,"QVPropertyHolder::getPropertyValue()"))
00338                                 if(ok != NULL) *ok = FALSE;
00339                         else
00340                                 if(ok != NULL) *ok = TRUE;
00341                         return variants[name].value<Type>();
00342                         }
00343 
00350                 QVariant getPropertyQVariantValue(const QString name, bool *ok = NULL) const;
00351 
00358                 template <class Type> Type getPropertyMaximum(const QString name, bool *ok = NULL) const
00359                         {
00360                         if(not checkExists(name,"QVPropertyHolder::getPropertyMaximum()"))
00361                                 if(ok != NULL) *ok = FALSE;
00362                         else if(not maximum.contains(name) and not minimum.contains(name))
00363                                 {
00364                                 QString str = QString("QVPropertyHolder::getPropertyMaximum():")
00365                                                           + QString(" property ") + name
00366                                                           + QString(" has no maximum value in ")
00367                                                           + QString("holder ") + getName() + QString(".");
00368                                 setLastError(str);
00369                                 if(qvApp->isRunning()) {
00370                                         std::cerr << qPrintable("Warning: " + str + "\n");
00371                                 } // Otherwise, qApp will show the error and won't start the program.
00372                                 if(ok != NULL) *ok = FALSE;
00373                                 }
00374                         else
00375                                 if(ok != NULL) *ok = TRUE;
00376                         return maximum[name].value<Type>();
00377                         }
00378 
00385                 template <class Type> Type getPropertyMinimum(const QString name, bool *ok = NULL) const
00386                         {
00387                         if(not checkExists(name,"QVPropertyHolder::getPropertyMinimum()"))
00388                                 if(ok != NULL) *ok = FALSE;
00389                         else if(not maximum.contains(name) and not minimum.contains(name))
00390                                 {
00391                                 QString str = QString("QVPropertyHolder::getPropertyMinimum():")
00392                                                           + QString(" property ") + name
00393                                                           + QString(" has no minimum value in ")
00394                                                           + QString("holder ") + getName() + QString(".");
00395                                 setLastError(str);
00396                                 if(qvApp->isRunning()) {
00397                                         std::cerr << qPrintable("Warning: " + str + "\n");
00398                                 } // Otherwise, qApp will show the error and won't start the program.
00399                                 if(ok != NULL) *ok = FALSE;
00400                                 }
00401                         else
00402                                 if(ok != NULL) *ok = TRUE;
00403                         return minimum[name].value<Type>();
00404                         }
00405 
00413                 QString getPropertyInfo(const QString name, bool *ok = NULL) const;
00414 
00420                 QString getLastError() const;
00421 
00429                 const QString infoInputProperties() const;
00430 
00442                 bool linkProperty(QString prop_orig,QVPropertyHolder *qvp_dest,QString prop_dest,LinkType link_type);
00443 
00449                 void unlink();
00450 
00451         protected:
00452 
00453                 template <class Type> bool setPropertyRange2(const QString name, const Type & minimum, const Type & maximum)
00454                         {
00455                         if(not checkExists(name,"QVPropertyHolder::setPropertyRange()"))
00456                                 return FALSE;
00457                         if(minimum <= getPropertyValue<Type>(name) and
00458                                 maximum >= getPropertyValue<Type>(name))
00459                                 {
00460                                         this->minimum[name] = QVariant::fromValue(minimum);
00461                                         this->maximum[name] = QVariant::fromValue(maximum);
00462                                         return TRUE;
00463                                 } else {
00464                                         QString str =  "QVPropertyHolder::setPropertyRange(): property " +
00465                                                                    name + " in holder " + getName() + " has value " +
00466                                                                    QString("%1").arg(getPropertyValue<Type>(name)) +
00467                                                                    ", which is not valid for the range [" +
00468                                                                    QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00469                                         setLastError(str);
00470                                         if(qvApp->isRunning()) {
00471                                                 std::cerr << qPrintable("Warning: " + str + "\n");
00472                                         } // Otherwise, qApp will show the error and won't start the program.
00473                                         return FALSE;
00474                                 }
00475                         }
00476 
00485                 void readInputProperties();
00486 
00498                 void writeOutputProperties();
00499 
00539                 template <class Type> bool parseArgument(const QString parameter, const QString value);
00540 
00549                 void setLastError(QString str) const;
00550 
00551         private:
00552                 QString name;
00553                 mutable QString errorString;
00554                 QMap<QString, QVariant> variants,safelyCopiedVariants;
00555                 QMap<QString, QVariant> minimum, maximum;
00556                 QMap<QString, QString> _info;
00557                 QMap<QString, PropertyInputOutputFlags> io_flags;
00558                 QMap<QString, PropertyLinkFlags> link_flags;
00559                 QList<QString> insertion_order;
00560 
00561                 QReadWriteLock RWLock;
00562                 class QVPropertyHolderLink {
00563                   public:
00564                         QVPropertyHolderLink(QVPropertyHolder *_qvp_orig,QString _prop_orig,QVPropertyHolder *_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) {
00565                                 // SyncSemaphoreIn value must initially be 1:
00566                                 SyncSemaphoreIn.release();
00567                                 // SyncSemaphoreOut is simply initialized with 0 (default value).
00568                         };
00569                         QVPropertyHolder *qvp_orig;
00570                         QString prop_orig;
00571                         QVPropertyHolder *qvp_dest;
00572                         QString prop_dest;
00573                         LinkType link_type;
00574                         QSemaphore SyncSemaphoreIn,SyncSemaphoreOut;
00575                         bool markedForDeletion;
00576                 };
00577                 QMap<QString, QVPropertyHolderLink* > inputLinks;
00578                 QMap<QString, QList<QVPropertyHolderLink*> > outputLinks;
00579 
00580                 template <class Type> bool setPropertyFromArguments(QString propertyName)
00581                         {
00582                         QStringList arguments = qvApp->arguments();
00583 
00584                         QMutableStringListIterator iterator(arguments);
00585                         while (iterator.hasNext())
00586                                 {
00587                                 QString argument = iterator.next();
00588                                 // Only if the name of the property holder is the same as defined in
00589                                 // the argument, in the form --name:property=value, (with name:
00590                                 // optional) the value will be intended to be applied to the property:
00591                                 if (argument.contains(QRegExp("^--")))
00592                                         {
00593                                         QString propertyHolderName(argument), parameter(argument), value(argument);
00594                                         // Checks whether in the argument string there is a name for
00595                                         // restricting the application of the value to a variable of
00596                                         // a specific property holder.
00597                                         if (argument.contains(QRegExp("^--[^=]+:")))
00598                                                 {
00599                                                 propertyHolderName.remove(QRegExp("^--")).remove(QRegExp(":.*"));
00600                                                 if(propertyHolderName != getName())
00601                                                         continue;
00602                                                 parameter.remove(QRegExp("^--[^=]+:")).remove(QRegExp("=.*$"));
00603                                                 }
00604                                         else
00605                                                 {
00606                                                 parameter.remove(QRegExp("^--")).remove(QRegExp("=.*$"));
00607                                                 }
00608                                         if(parameter != propertyName)
00609                                                 continue;
00610                                         // If we get here, then we must assign the value to the property:
00611                                         value.remove(QRegExp("^--[^=]*="));
00612 
00613 
00614                                         /*std::cerr << "VOY A PROCESAR " << qPrintable(QString(parameter)) << " " << qPrintable(QString(value)) << " EN " << qPrintable(propertyName) << "\n";*/
00615 
00616 
00617                                         if(parseArgument<Type>(parameter,value))
00618                                                 {
00619                                                 if(not isInput(propertyName))
00620                                                         {
00621                                                         QString str = QString("QVPropertyHolder::setPropertyFromArguments():")
00622                                                                                 + QString(" property ") + propertyName
00623                                                                                 + QString(" in holder ") + getName()
00624                                                                                 + QString(" is not of Input type, and cannot be parsed.");
00625                                                         setLastError(str);
00626                                                         //qApp will show the error and won't start the program.
00627                                                         }
00628                                                 qvApp->setArgumentAsUsed(argument);
00629                                                 return TRUE;
00630                                                 }
00631                                         }
00632                                 }
00633                                 // If we get here, then we did not parse any value for the property:
00634                                 return FALSE;
00635                         }
00636 
00637                 bool correctRange(const QString name, const double & value) const;
00638                 // Any type inference ambiguity resolved with this:
00639                 // 1. For int values:
00640                 bool correctRange(const char *name, const int & value) const;
00641                 bool correctRange(QString name, const int & value) const;
00642 
00643                 // 2. Rest of types have no range, so we always return true:
00644                 template <typename T> bool correctRange(const QString parameter, const T & value) {
00645                         Q_UNUSED(parameter);
00646                         Q_UNUSED(value);
00647                         return TRUE;
00648                 }
00649 
00650                 bool checkExists(const QString name, const QString methodname) const;
00651                 bool checkIsNewProperty(const QString name, const QString methodname) const;
00652         };
00653 
00654 template <class Type> bool QVPropertyHolder::parseArgument(const QString parameter, const QString value)
00655         {
00656                 errorString = "QVPropertyHolder::parseArgument(): holder " + getName() +
00657                                                 ": parameter " + parameter +
00658                                                 " has an unknown type to command line parser " +
00659                                                 QString("(trying to parse value %1)").arg(value) ;
00660                 return FALSE;
00661         }
00662 
00663 template <> bool QVPropertyHolder::parseArgument<bool>(const QString parameter, const QString value);
00664 
00665 template <> bool QVPropertyHolder::parseArgument<int>(const QString parameter, const QString value);
00666 
00667 template <> bool QVPropertyHolder::parseArgument<double>(const QString parameter, const QString value);
00668 
00669 template <> bool QVPropertyHolder::parseArgument<QString>(const QString parameter, const QString value);
00670 
00671 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyHolder::PropertyInputOutputFlags)
00672 Q_DECLARE_OPERATORS_FOR_FLAGS(QVPropertyHolder::PropertyLinkFlags)
00673 
00674 #endif

Generated on Thu Dec 13 13:06:25 2007 for QVision by  doxygen 1.5.3