src/qvcore/qvpropertyholder.cpp

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 #include "qvpropertyholder.h"
00026 
00027 QVPropertyHolder::QVPropertyHolder(const QString name):
00028         name(name), errorString(), variants(), safelyCopiedVariants(), minimum(),
00029         maximum(), _info(), io_flags(), link_flags(), insertion_order(),
00030         inputLinks(), outputLinks()
00031         {
00032         if(qvApp == NULL)
00033                 {
00034                 QString str = "QVPropertyHolder::QVPropertyHolder(): holder " + name +
00035                                           ": property holders cannot be created before the " +
00036                                           "QVApplication instance. Aborting now.";
00037                 std::cerr << qPrintable(str) << std::endl;
00038                 exit(1);
00039                 }
00040         else
00041                 qvApp->registerQVPropertyHolder(this);
00042         }
00043 
00044 QVPropertyHolder::~QVPropertyHolder()
00045 {
00046         if(qvApp != NULL)
00047                 qvApp->deregisterQVPropertyHolder(this);
00048         // Not needed now: unlink();
00049 }
00050 
00051 void QVPropertyHolder::setName(const QString name)
00052         { this->name = name; }
00053 
00054 const QString QVPropertyHolder::getName() const
00055         { return this->name; }
00056 
00057 QList<QString> QVPropertyHolder::getPropertyList() const
00058         { return variants.keys(); }
00059 
00060 bool QVPropertyHolder::containsProperty(const QString name) const
00061         { return variants.contains(name); }
00062 
00063 QVariant::Type QVPropertyHolder::getPropertyType(const QString name, bool *ok) const
00064         {
00065         if(not checkExists(name,"QVPropertyHolder::getPropertyType()"))
00066                 {
00067                 if(ok != NULL) *ok = FALSE;
00068                 return QVariant::Invalid;
00069                 }
00070         if(ok != NULL) *ok = TRUE;
00071         QVariant variant = variants.value(name);
00072         return variant.type();
00073         }
00074 
00075 bool QVPropertyHolder::removeProperty(const QString name)
00076         {
00077         if(not checkExists(name,"QVPropertyHolder::removeProperty()"))
00078                 return FALSE;
00079         this->variants.remove(name);
00080         this->safelyCopiedVariants.remove(name);
00081         this->minimum.remove(name);
00082         this->maximum.remove(name);
00083         this->_info.remove(name);
00084         this->io_flags.remove(name);
00085         int i = this->insertion_order.indexOf(name);
00086         this->insertion_order.removeAt(i);
00087         return TRUE;
00088         }
00089 
00090 bool QVPropertyHolder::setPropertyRange(const QString name, const double & minimum, const double & maximum)
00091         {
00092         std::cerr << "WARNING: setPropertyRange() is deprecated. Specify range in the function addProperty instead." << std::endl;
00093         if(not checkExists(name,"QVPropertyHolder::setPropertyRange()"))
00094                 return FALSE;
00095         if(minimum <= getPropertyValue<double>(name) and
00096                 maximum >= getPropertyValue<double>(name))
00097                 {
00098                         this->minimum[name] = QVariant::fromValue(minimum);
00099                         this->maximum[name] = QVariant::fromValue(maximum);
00100                         return TRUE;
00101                 } else {
00102                         QString str =  "QVPropertyHolder::setPropertyRange(): property " +
00103                                                    name + " in holder " + getName() + " has value " +
00104                                                    QString("%1").arg(getPropertyValue<double>(name)) +
00105                                                    ", which is not valid for the range [" +
00106                                                    QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00107                         setLastError(str);
00108                         if(qvApp->isRunning()) {
00109                                 std::cerr << qPrintable("Warning: " + str + "\n");
00110                         } // Otherwise, qApp will show the error and won't start the program.
00111                         return FALSE;
00112                 }
00113         }
00114 
00115 bool QVPropertyHolder::setPropertyRange(QString name, int & minimum, int & maximum)
00116         { return setPropertyRange(name, static_cast<double>(minimum), static_cast<double>(maximum)); }
00117 
00118 bool QVPropertyHolder::hasRange(const QString name)
00119         { return maximum.contains(name) and minimum.contains(name); }
00120 
00121 bool QVPropertyHolder::isInput(const QString name)
00122         { return (io_flags[name] & inputFlag);};
00123 
00124 bool QVPropertyHolder::isOutput(const QString name)
00125         { return (io_flags[name] & outputFlag);};
00126 
00127 bool QVPropertyHolder::isLinkedInput(const QString name)
00128         { return (link_flags[name] & linkedInputFlag);};
00129 
00130 bool QVPropertyHolder::isLinkedOutput(const QString name)
00131         { return (link_flags[name] & linkedOutputFlag);};
00132 
00133 QVariant QVPropertyHolder::getPropertyQVariantValue(const QString name, bool *ok) const
00134         {
00135         if (not checkExists(name,"QVPropertyHolder::getPropertyQVariantValue()"))
00136                 if(ok != NULL) *ok = FALSE;
00137         else
00138                 if(ok != NULL) *ok = TRUE;
00139         return variants[name];
00140         }
00141 
00142 QString QVPropertyHolder::getPropertyInfo(const QString name, bool *ok) const
00143         {
00144         if(not checkExists(name,"QVPropertyHolder::getPropertyInfo()"))
00145                 if(ok != NULL) *ok = FALSE;
00146         else
00147                 if(ok != NULL) *ok = TRUE;
00148         return this->_info[name];
00149         }
00150 
00151 QString QVPropertyHolder::getLastError() const
00152 {
00153         return errorString;
00154 }
00155 
00156 const QString QVPropertyHolder::infoInputProperties() const
00157         {
00158         QString info = QString("Input parameters for ") + getName() + QString(":\n");
00159         bool emptyInfo=TRUE;
00160 
00161         QStringList props;
00162         QListIterator<QString> i(insertion_order);
00163         while (i.hasNext())
00164                 {
00165                 QString property = i.next();
00166                 if(not (io_flags[property] & inputFlag) or (link_flags[property] & linkedInputFlag))
00167                         continue;
00168                 emptyInfo=FALSE;
00169                 info += "  --" + property + "=";
00170                 QVariant::Type type = getPropertyType(property);
00171                 switch(type)
00172                         {
00173                         case QVariant::String:
00174                                 {
00175                                 READ_PROPERTY(this, QString, property, stringValue);
00176                                 info += "[text] ";
00177                                 if(stringValue != QString())
00178                                         info += "(def. " + stringValue + ") ";
00179                                 }
00180                                 break;
00181                         case QVariant::Double:
00182                                 {
00183                                 READ_PROPERTY(this,double,property,doubleValue);
00184                                 if(maximum.contains(property) and minimum.contains(property))
00185                                         {
00186                                         READ_PROPERTY_MAX(this,double,property,doubleMaximum);
00187                                         READ_PROPERTY_MIN(this,double,property,doubleMinimum);
00188                                         info += "[" + QString().setNum(doubleMinimum) + "..."
00189                                                 + QString().setNum(doubleMaximum) + "] ";
00190                                         }
00191                                 else
00192                                         info += "[double] ";
00193                                 info += "(def. "+ QString().setNum(doubleValue) + ") ";
00194                                 }
00195                                 break;
00196                         case QVariant::Int:
00197                                 {
00198                                 READ_PROPERTY(this,int,property,intValue);
00199                                 if(maximum.contains(property) and minimum.contains(property))
00200                                         {
00201                                         READ_PROPERTY_MAX(this,int,property,intMaximum);
00202                                         READ_PROPERTY_MIN(this,int,property,intMinimum);
00203                                         info += "[" + QString().setNum(intMinimum) + "..."
00204                                                 + QString().setNum(intMaximum) + "] ";
00205                                         }
00206                                 else
00207                                         info += "[int] ";
00208                                         info += "(def. "+ QString().setNum(intValue) + ") ";
00209                                 }
00210                                 break;
00211                         case QVariant::Bool:
00212                                 {
00213                                 READ_PROPERTY(this, bool, property, boolValue);
00214                                 info += "[true,false]"
00215                                         + (boolValue ? QString(" (def. true) "):QString("(def. false) "));
00216                                 }
00217                                 break;
00218                         default:
00219                                 info += QString("[%1] ").arg(type);
00220                                 break;
00221                         }
00222                 QString propertyInfo = getPropertyInfo(property);
00223                 if (propertyInfo != QString())
00224                         propertyInfo = " " + propertyInfo + ". ";
00225                 info += propertyInfo.rightJustified(80-info.split('\n').last().length(),'.') + "\n";
00226                 }
00227         if(emptyInfo)
00228                 return QString(""); //info += "  None.\n";
00229 
00230         return info;
00231         }
00232 
00233 bool QVPropertyHolder::correctRange(const QString name, const double & value) const
00234         {
00235         if(not maximum.contains(name) and not minimum.contains(name))
00236                 return TRUE;
00237         double maximum = getPropertyMaximum<double>(name);
00238         double minimum = getPropertyMinimum<double>(name);
00239         if(minimum <= value and maximum >= value)
00240                 return TRUE;
00241         else
00242                 {
00243                 QString str =  "QVPropertyHolder::setPropertyValue(): value " +
00244                                            QString("%1").arg(value) + " for property " +
00245                                            name + " in holder " + getName() +
00246                                            "is not valid for the range [" +
00247                                            QString("%1,%2").arg(minimum).arg(maximum) + 
00248                                            "] stablished for it." ;
00249                 setLastError(str);
00250                 if(qvApp->isRunning())
00251                         {
00252                         std::cerr << qPrintable("Warning: " + str + "\n");
00253                         } // Otherwise, qApp will show the error and won't start the program.
00254                 return FALSE;
00255                 }
00256         }
00257 
00258 bool QVPropertyHolder::correctRange(const char *name, const int & value) const
00259         { return correctRange(QString(name),static_cast<double>(value)); }
00260 
00261 bool QVPropertyHolder::correctRange(QString name, const int & value) const
00262         { return correctRange(name,static_cast<double>(value)); }
00263 
00264 bool QVPropertyHolder::checkExists(const QString name, const QString methodname) const
00265         {
00266         if(not variants.contains(name))
00267                 {
00268                 QString str =  methodname + ": property " + name +
00269                                            " doesn't exists in holder " + getName() + ".";
00270                 setLastError(str);
00271                 if(qvApp->isRunning()) {
00272                         std::cerr << qPrintable("Warning: " + str + "\n");
00273                 } // Otherwise, qApp will show the error and won't start the program.
00274                 return FALSE;
00275                 } else {
00276                 return TRUE;
00277                 }
00278         }
00279 
00280 bool QVPropertyHolder::checkIsNewProperty(const QString name, const QString methodname) const
00281         {
00282         if(variants.contains(name))
00283                 {
00284                 QString str =  methodname + "(): property " + name +
00285                                            " already exists in holder " + getName() + ".";
00286                 setLastError(str);
00287                 if(qvApp->isRunning()) {
00288                         std::cerr << qPrintable("Warning: " + str + "\n");
00289                 } // Otherwise, qApp will show the error and won't start the program.
00290                 return FALSE;
00291                 } else {
00292                 return TRUE;
00293                 }
00294         }
00295 
00296 bool QVPropertyHolder::linkProperty(QString prop_orig, QVPropertyHolder *qvp_dest, QString prop_dest, LinkType link_type)
00297         {
00298         bool ok1,ok2;
00299         QString errMsg;
00300         QVariant::Type t1,t2;
00301         QVPropertyHolder *qvp_orig=this, *qvp_err=NULL;
00302         
00303         t1 = qvp_orig->getPropertyType(prop_orig,&ok1);
00304         t2 = qvp_dest->getPropertyType(prop_dest,&ok2);
00305         if(qvApp->isRunning())
00306                 {
00307                 qvp_err = qvp_orig;
00308                 errMsg = QString("QVPropertyHolder::linkProperty(): Property holder %1:"
00309                                         "Cannot link properties after launching QVApplication.\n")
00310                                         .arg(prop_orig).arg(qvp_orig->getName());
00311                 }
00312         else if(qvp_orig == qvp_dest)
00313                 {
00314                 errMsg = QString("QVPropertyHolder::linkProperty(): Property holder %1: cannot link a QVPropertyHolder with itself.\n").arg(qvp_orig->getName());
00315                 qvp_err = qvp_orig;
00316                 }
00317         else if(not ok1)
00318                 {
00319                 errMsg = QString("QVPropertyHolder::linkProperty(): Property %1 does not exist in property holder %2.\n")
00320                                 .arg(prop_orig).arg(qvp_orig->getName());
00321                 qvp_err = qvp_orig;
00322                 }
00323         else if (not ok2)
00324                 {
00325                 errMsg = QString("QVPropertyHolder::linkProperty(): Property %1 does not exist in property holder %2.\n")
00326                                 .arg(prop_dest).arg(qvp_dest->getName());
00327                 qvp_err = qvp_dest;
00328                 }
00329         else if(t1 != t2)
00330                 {
00331                 errMsg = QString("QVPropertyHolder::linkProperty(): Properties %1 and %2 of QVPropertyHolders %3 and %4 respectively are not of the same type.\n").arg(prop_orig).arg(prop_dest).arg(qvp_orig->getName()).arg(qvp_dest->getName());
00332                 qvp_err = qvp_orig;
00333                 }
00334         else if(not (qvp_orig->io_flags[prop_orig] & outputFlag))
00335                 {
00336                 errMsg = QString("QVPropertyHolder::linkProperty(): Property %1 of property holder %2 is not of Output type, and cannot be linked as such.\n").arg(prop_orig).arg(qvp_orig->getName());
00337                 qvp_err = qvp_orig;
00338                 }
00339         else if(not (qvp_dest->io_flags[prop_dest] & inputFlag))
00340                 {
00341                 errMsg = QString("QVPropertyHolder::linkProperty(): Property %1 property holder %2 is not of Input type, and cannot be linked as such.\n").arg(prop_dest).arg(qvp_dest->getName());
00342                 qvp_err = qvp_dest;
00343                 }
00344 
00345         if(errMsg != QString())
00346                 {
00347                 qvp_err->setLastError(errMsg);
00348                 if(qvApp->isRunning()) {
00349                         std::cerr << qPrintable("Warning: " + errMsg + "\n");
00350                 } // Otherwise, qApp will show the error and won't start the program.
00351                 return FALSE;
00352                 }
00353         else
00354                 {
00355                 QVPropertyHolderLink *link = new
00356                          QVPropertyHolderLink(qvp_orig,prop_orig,qvp_dest,prop_dest,link_type);
00357                                 qvp_orig->outputLinks[prop_orig].push_back(link);
00358                                 qvp_dest->inputLinks[prop_dest] = link;
00359                 qvp_dest->link_flags[prop_dest] |= linkedInputFlag;
00360                 qvp_orig->link_flags[prop_orig] |= linkedOutputFlag;
00361                 return TRUE;
00362                 }
00363         }
00364 
00365 void QVPropertyHolder::unlink()
00366         {
00367                 QMapIterator<QString, QVPropertyHolderLink*> i_in(inputLinks);
00368                 while (i_in.hasNext()) {
00369                         i_in.next();
00370                         QVPropertyHolderLink *link = i_in.value();
00371                         link->markedForDeletion = TRUE;
00372                         // Protect against a possible pending acquire() from our input
00373                         // in other holders:
00374                         link->SyncSemaphoreIn.release();
00375                 }
00376         
00377                 QMapIterator<QString, QList<QVPropertyHolderLink*> >i_out(outputLinks);
00378                 while (i_out.hasNext()) {
00379                         i_out.next();
00380                         QListIterator<QVPropertyHolderLink*> j_out(i_out.value());
00381                         while(j_out.hasNext()) {
00382                                 QVPropertyHolderLink *link = j_out.next();
00383                                 link->markedForDeletion = TRUE;
00384                                 // Protect against a possible pending acquire() for our output
00385                                 // in other holders:
00386                                 link->SyncSemaphoreOut.release();
00387                         }
00388                 }
00389         }
00390 
00391 void QVPropertyHolder::readInputProperties()
00392         {
00393         // We read every linked input property from its source, protecting
00394         // the read with a standard RWLock (that here we just lock for read).
00395         // The only caveat is that if a property is synchronously read, then
00396         // we must wait for the producer to write it first. We implement that
00397         // by waiting on the SyncSemaphoreOut of the link. Also, in this
00398         // case when we finish reading the property, we signal every possible
00399         // waiting writer that, regarding this specific link, it can write now
00400         // a new value if it needs to, because we have read the old value yet.
00401         // This is implemented by releasing the SyncSemaphoreIn associated to
00402         // the link.
00403         QMutableMapIterator<QString, QVPropertyHolderLink*> i(inputLinks);
00404         while (i.hasNext()) {
00405                 i.next();
00406                 QVPropertyHolderLink *link = i.value();
00407                 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00408                         link->SyncSemaphoreOut.acquire();
00409                 }
00410                 link->qvp_orig->RWLock.lockForRead();
00411                 //this->setPropertyValueQVariant(link->prop_dest,link->qvp_orig->safelyCopiedVariants[link->prop_orig]);
00412                 this->variants[link->prop_dest] = link->qvp_orig->safelyCopiedVariants[link->prop_orig];
00413                 link->qvp_orig->RWLock.unlock();
00414                 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00415                         link->SyncSemaphoreIn.release();
00416                 }
00417                 // Possible link deletion:
00418                 if(link->markedForDeletion) {
00419                         i.remove();
00420                         delete link;
00421                 }
00422         }
00423 }
00424 
00425 void QVPropertyHolder::writeOutputProperties()
00426         {
00427         QMutableMapIterator<QString, QList<QVPropertyHolderLink*> >i(outputLinks);
00428 
00429         // For every QVP synchronously linked to this QVP's output, we ask
00430         // for permision to write a new output (that will only be possible if
00431         // all of these QVP's have read their inputs already):
00432         while (i.hasNext()) {
00433                 i.next();
00434                 QListIterator<QVPropertyHolderLink*> j(i.value());
00435                 while(j.hasNext()) {
00436                         QVPropertyHolderLink *link = j.next();
00437                         if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00438                                 link->SyncSemaphoreIn.acquire();
00439                         }
00440                 }
00441         }
00442 
00443         // Now, we write a new coherent state, simply protected by the
00444         // corresponding RWLock:
00445         i.toFront();
00446         this->RWLock.lockForWrite();
00447         while (i.hasNext()) {
00448                 i.next();
00449                 QString prop_orig = i.key();
00450                 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00451         }
00452         this->RWLock.unlock();
00453 
00454         // Finally, we signal to QVP's synchronously linked to this QVP's output
00455         // that there is a new coherent output, by unlocking our SyncLockOut
00456         // lock.
00457         i.toFront();
00458         while (i.hasNext()) {
00459                 i.next();
00460                 QMutableListIterator<QVPropertyHolderLink*> j(i.value());
00461                 while(j.hasNext()) {
00462                         QVPropertyHolderLink *link = j.next();
00463                         if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00464                                 link->SyncSemaphoreOut.release();
00465                         }
00466                         // Possible link deletion:
00467                         if(link->markedForDeletion) {
00468                                 j.remove();
00469                                 delete link;
00470                                 if(i.value().isEmpty()) {
00471                                         i.remove();
00472                                         break;
00473                                 }
00474                         }
00475                 }
00476         }
00477 }
00478 
00479 void QVPropertyHolder::setLastError(QString str) const
00480         { errorString = str; }
00481 
00482 template <> bool QVPropertyHolder::parseArgument<bool>(const QString parameter, const QString value)
00483         {
00484         if (value.toLower() == "true" || value.toLower() == "false")
00485                 {
00486                 //variants[parameter] = QVariant::fromValue<bool>(value.toLower() == "true");
00487                 setPropertyValue<bool>(parameter,value.toLower() == "true");
00488                 return TRUE;
00489                 }
00490         else {
00491                 errorString = "QVPropertyHolder::parseArgument(): holder " + getName() +
00492                                         ": value " + value +
00493                                         " is not a valid boolean value for parameter " +
00494                                         parameter + ".\n";
00495                 return FALSE;
00496                 }
00497         }
00498 
00499 template <> bool QVPropertyHolder::parseArgument<int>(const QString parameter, const QString value)
00500         {
00501         bool okInt;
00502         int intValue = value.toInt(&okInt);
00503         if(not okInt)
00504                 {
00505                 errorString = "QVPropertyHolder::parseArgument(): holder " + getName() +
00506                                         ": value " + value +
00507                                         " is not a valid integer value for parameter " +
00508                                         parameter + ".\n";
00509                 return FALSE;
00510                 }
00511         //variants[parameter] = QVariant::fromValue<int>(intValue);
00512         setPropertyValue<int>(parameter,intValue);
00513         return TRUE;
00514         }
00515 
00516 template <> bool QVPropertyHolder::parseArgument<double>(const QString parameter, const QString value)
00517         {
00518         bool okDouble;
00519         double doubleValue = value.toDouble(&okDouble);
00520         if(not okDouble)
00521                 {
00522                 errorString = "QVPropertyHolder::parseArgument(): holder " + getName() +
00523                                         ": value " + value +
00524                                         " is not a valid double value for parameter " +
00525                                         parameter + ".\n";
00526                 return FALSE;
00527                 }
00528         //variants[parameter] = QVariant::fromValue<double>(doubleValue);
00529         setPropertyValue<double>(parameter,doubleValue);
00530         return TRUE;
00531         }
00532 
00533 template <> bool QVPropertyHolder::parseArgument<QString>(const QString parameter, const QString value)
00534         {
00535         //variants[parameter] = QVariant::fromValue<QString>(value);
00536         setPropertyValue<QString>(parameter,value);
00537         return TRUE;
00538         }

Generated on Wed Jan 16 18:41:28 2008 for QVision by  doxygen 1.5.3