src/qvcore/qvpropertycontainer.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008. 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 <QVDisjointSet>
00026 #include <QVPropertyContainer>
00027 
00028 uint QVPropertyContainer::maxIdent = 0;
00029 // QVPropertyContainerInformer QVPropertyContainer::globalInformer;
00030 
00031 QVPropertyContainer::QVPropertyContainer(const QString name):
00032         name(name), errorString(), variants(), safelyCopiedVariants(), minimum(),
00033         maximum(), _info(), io_flags(), link_flags(), insertion_order(),
00034         inputLinks(), outputLinks()
00035         {
00036         ident = getNewIdent();
00037         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ")";
00038         if(qvApp == NULL)
00039                 {
00040                 QString str = "QVPropertyContainer::QVPropertyContainer(): holder " + name +
00041                                           ": property holders cannot be created before the " +
00042                                           "QVApplication instance. Aborting now.";
00043                 std::cerr << qPrintable(str) << std::endl;
00044                 exit(1);
00045                 }
00046         else
00047                 {
00048                 qvApp->registerQVPropertyContainer(this);
00049 //              QVPropertyContainer::globalInformer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::ContainerAdd));
00050                 }
00051         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ") <- return";
00052         }
00053 
00054 QVPropertyContainer::QVPropertyContainer(const QVPropertyContainer &cont):
00055         name(cont.name), ident(cont.ident), errorString(cont.errorString), variants(cont.variants),
00056         safelyCopiedVariants(cont.safelyCopiedVariants), minimum(cont.minimum), maximum(cont.maximum),
00057         _info(cont._info), io_flags(cont.io_flags), link_flags(cont.link_flags), insertion_order(cont.insertion_order),
00058         RWLock(), inputLinks(cont.inputLinks), outputLinks(cont.outputLinks) 
00059         {
00060         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ")";
00061         if(qvApp == NULL)
00062                 {
00063                 QString str = "QVPropertyContainer::QVPropertyContainer(): holder " + name +
00064                                           ": property holders cannot be created before the " +
00065                                           "QVApplication instance. Aborting now.";
00066                 std::cerr << qPrintable(str) << std::endl;
00067                 exit(1);
00068                 }
00069         else
00070                 {
00071                 qvApp->registerQVPropertyContainer(this);
00072 //              QVPropertyContainer::globalInformer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::ContainerAdd));
00073                 }
00074         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ") <- return";
00075         }
00076 
00077 QVPropertyContainer & QVPropertyContainer::operator=(const QVPropertyContainer &cont)
00078         {
00079         name = cont.name;
00080         ident = cont.ident;
00081         errorString = cont.errorString;
00082         variants = cont.variants;
00083         safelyCopiedVariants = cont.safelyCopiedVariants;
00084         minimum = cont.minimum;
00085         maximum = cont.maximum;
00086         _info = cont._info;
00087         io_flags = cont.io_flags;
00088         link_flags = cont.link_flags;
00089         insertion_order = cont.insertion_order;
00090         inputLinks = cont.inputLinks;
00091         outputLinks = cont.outputLinks;
00092 
00093         informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::All));
00094         return *this;
00095         }
00096 
00097 QVPropertyContainer::~QVPropertyContainer()
00098         {
00099         if(qvApp != NULL)
00100                 qvApp->deregisterQVPropertyContainer(this);
00102         unlink();
00103         informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::ContainerDel));
00104         }
00105 
00106 void QVPropertyContainer::setName(const QString name)
00107         { this->name = name; informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::Name)); }
00108 
00109 const QString QVPropertyContainer::getName() const
00110         { return this->name; }
00111 
00112 const uint QVPropertyContainer::getId() const
00113         { return this->ident; }
00114 
00115 bool QVPropertyContainer::operator==(const QVPropertyContainer &cont) const
00116         { return (ident == cont.ident); }
00117 
00118 QList<QString> QVPropertyContainer::getPropertyList() const
00119         { return variants.keys(); }
00120 
00121 bool QVPropertyContainer::containsProperty(const QString name) const
00122         { return variants.contains(name); }
00123 
00124 int QVPropertyContainer::getPropertyType(const QString name, bool *ok) const
00125         {
00126         if(not checkExists(name,"QVPropertyContainer::getPropertyType()"))
00127                 {
00128                 if(ok != NULL) *ok = FALSE;
00129                 return QVariant::Invalid;
00130                 }
00131         if(ok != NULL) *ok = TRUE;
00132         QVariant variant = variants.value(name);
00133         return variant.userType();
00134         }
00135 
00136 bool QVPropertyContainer::removeProperty(const QString name)
00137         {
00138         if(not checkExists(name,"QVPropertyContainer::removeProperty()"))
00139                 return FALSE;
00140         this->variants.remove(name);
00141         this->safelyCopiedVariants.remove(name);
00142         this->minimum.remove(name);
00143         this->maximum.remove(name);
00144         this->_info.remove(name);
00145         this->io_flags.remove(name);
00146         int i = this->insertion_order.indexOf(name);
00147         this->insertion_order.removeAt(i);
00148         informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::PropertyDel, name));
00149         return TRUE;
00150         }
00151 /*
00152 bool QVPropertyContainer::setPropertyRange(const QString name, const double & minimum, const double & maximum)
00153         {
00154         std::cerr << "WARNING: setPropertyRange() is deprecated. Specify range in the function addProperty instead." << std::endl;
00155         if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00156                 return FALSE;
00157         if(minimum <= getPropertyValue<double>(name) and
00158                 maximum >= getPropertyValue<double>(name))
00159                 {
00160                         this->minimum[name] = QVariant::fromValue(minimum);
00161                         this->maximum[name] = QVariant::fromValue(maximum);
00162                         return TRUE;
00163                 } else {
00164                         QString str =  "QVPropertyContainer::setPropertyRange(): property " +
00165                                                    name + " in holder " + getName() + " has value " +
00166                                                    QString("%1").arg(getPropertyValue<double>(name)) +
00167                                                    ", which is not valid for the range [" +
00168                                                    QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00169                         setLastError(str);
00170                         if(qvApp->isRunning()) {
00171                                 std::cerr << qPrintable("Warning: " + str + "\n");
00172                         } // Otherwise, qApp will show the error and won't start the program.
00173                         return FALSE;
00174                 }
00175         }
00176 
00177 bool QVPropertyContainer::setPropertyRange(QString name, int & minimum, int & maximum)
00178         { return setPropertyRange(name, static_cast<double>(minimum), static_cast<double>(maximum)); }
00179 */
00180 bool QVPropertyContainer::hasRange(const QString name) const
00181         { return maximum.contains(name) and minimum.contains(name); }
00182 
00183 bool QVPropertyContainer::isInput(const QString name) const
00184         { return (io_flags[name] & inputFlag);};
00185 
00186 bool QVPropertyContainer::isOutput(const QString name) const
00187         { return (io_flags[name] & outputFlag);};
00188 
00189 bool QVPropertyContainer::isGUIInvisible(const QString name) const
00190         { return (io_flags[name] & guiInvisible);};
00191 
00192 bool QVPropertyContainer::isLinkedInput(const QString name) const
00193         { return (link_flags[name] & linkedInputFlag);};
00194 
00195 bool QVPropertyContainer::isLinkedOutput(const QString name) const
00196         { return (link_flags[name] & linkedOutputFlag);};
00197 
00198 QVariant QVPropertyContainer::getPropertyQVariantValue(const QString name, bool *ok) const
00199         {
00200         if (not checkExists(name,"QVPropertyContainer::getPropertyQVariantValue()"))
00201                 if(ok != NULL) *ok = FALSE;
00202         else
00203                 if(ok != NULL) *ok = TRUE;
00204         return variants[name];
00205         }
00206 
00207 QString QVPropertyContainer::getPropertyInfo(const QString name, bool *ok) const
00208         {
00209         if(not checkExists(name,"QVPropertyContainer::getPropertyInfo()"))
00210                 if(ok != NULL) *ok = FALSE;
00211         else
00212                 if(ok != NULL) *ok = TRUE;
00213         return this->_info[name];
00214         }
00215 
00216 QString QVPropertyContainer::getLastError() const
00217         {
00218         return errorString;
00219         }
00220 
00221 const QString QVPropertyContainer::infoInputProperties() const
00222         {
00223         qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ")";
00224 
00225         QString info = QString("Input parameters for ") + getName() + QString(":\n");
00226         bool emptyInfo=TRUE;
00227 
00228         qDebug() << "QVPropertyContainer::infoInputProperties(): Properties " << insertion_order;
00229 
00230         foreach (QString property, insertion_order)
00231         //QListIterator<QString> i(insertion_order);
00232         //while (i.hasNext())
00233                 {
00234                 //const QString property = i.next();
00235 
00236                 if( not isInput(property) )
00237                         continue;
00238 
00239                 bool printableProperty = TRUE;
00240                 QString propertyInfo("  --" + property + "=");
00241 
00242                 switch(getPropertyType(property))
00243                         {
00244                         case QVariant::String:
00245                                 propertyInfo += QString() + "[text] " + "(def. '" + getPropertyValue<QString>(property) + "') ";
00246                                 break;
00247 
00248                         case QVariant::Double:
00249                                 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00250                                         "[" + QString().setNum(getPropertyMinimum<double>(property)) + "..."
00251                                                 + QString().setNum(getPropertyMaximum<double>(property)) + "] ":
00252                                         "[double] " ) + "(def. "+ QString().setNum(getPropertyValue<double>(property)) + ") ";
00253                                 break;
00254 
00255                         case QVariant::Int:
00256                                 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00257                                         "[" + QString().setNum(getPropertyMinimum<int>(property)) + "..." +
00258                                                 QString().setNum(getPropertyMaximum<int>(property)) + "] ":
00259                                         "[int] " ) + "(def. "+ QString().setNum(getPropertyValue<int>(property)) + ") ";
00260                                 break;
00261 
00262                         case QVariant::Bool:
00263                                 propertyInfo += "[true,false]" + (getPropertyValue<bool>(property) ?
00264                                                                 QString(" (def. true) "):QString("(def. false) "));
00265                                 break;
00266 
00267                         default:
00268                                 printableProperty = FALSE;
00269                                 break;
00270                         }
00271 
00272                 if (printableProperty)
00273                         {
00274                         info += propertyInfo + getPropertyInfo(property).rightJustified(100-propertyInfo.split('\n').last().length(),' ') + ".\n";
00275                         emptyInfo=FALSE;
00276                         }
00277                 }
00278 
00279         qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ") <~ return";
00280 
00281         if(emptyInfo)
00282                 return QString("");
00283         
00284         return info;
00285         }
00286 
00287 bool QVPropertyContainer::correctRange(const QString name, const double & value) const
00288         {
00289         if(not maximum.contains(name) and not minimum.contains(name))
00290                 return TRUE;
00291         double maximum = getPropertyMaximum<double>(name);
00292         double minimum = getPropertyMinimum<double>(name);
00293         if(minimum <= value and maximum >= value)
00294                 return TRUE;
00295         else
00296                 {
00297                 QString str =  "QVPropertyContainer::setPropertyValue(): value " +
00298                                            QString("%1").arg(value) + " for property " +
00299                                            name + " in holder " + getName() +
00300                                            "is not valid for the range [" +
00301                                            QString("%1,%2").arg(minimum).arg(maximum) + 
00302                                            "] stablished for it." ;
00303                 setLastError(str);
00304                 if(qvApp->isRunning())
00305                         {
00306                         std::cerr << qPrintable("Warning: " + str + "\n");
00307                         } // Otherwise, qApp will show the error and won't start the program.
00308                 return FALSE;
00309                 }
00310         }
00311 
00312 bool QVPropertyContainer::correctRange(const char *name, const int & value) const
00313         { return correctRange(QString(name),static_cast<double>(value)); }
00314 
00315 bool QVPropertyContainer::correctRange(QString name, const int & value) const
00316         { return correctRange(name,static_cast<double>(value)); }
00317 
00318 bool QVPropertyContainer::checkExists(const QString name, const QString methodname) const
00319         {
00320         if(not variants.contains(name))
00321                 {
00322                 QString str =  methodname + ": property " + name +
00323                                            " doesn't exists in holder " + getName() + ".";
00324                 setLastError(str);
00325                 if(qvApp->isRunning()) {
00326                         std::cerr << qPrintable("Warning: " + str + "\n");
00327                 } // Otherwise, qApp will show the error and won't start the program.
00328                 return FALSE;
00329                 } else {
00330                 return TRUE;
00331                 }
00332         }
00333 
00334 bool QVPropertyContainer::checkIsNewProperty(const QString name, const QString methodname) const
00335         {
00336         if(variants.contains(name))
00337                 {
00338                 QString str =  methodname + "(): property " + name +
00339                                            " already exists in holder " + getName() + ".";
00340                 setLastError(str);
00341                 if(qvApp->isRunning()) {
00342                         std::cerr << qPrintable("Warning: " + str + "\n");
00343                 } // Otherwise, qApp will show the error and won't start the program.
00344                 return FALSE;
00345                 } else {
00346                 return TRUE;
00347                 }
00348         }
00349 
00350 bool QVPropertyContainer::linkProperty(QString prop_orig, QVPropertyContainer *qvp_dest, QString prop_dest, LinkType link_type)
00351         {
00352         bool ok1,ok2;
00353         QString errMsg;
00354         int t1,t2;
00355         QVPropertyContainer *qvp_err=NULL;
00356         
00357         t1 = this->getPropertyType(prop_orig,&ok1);
00358         t2 = qvp_dest->getPropertyType(prop_dest,&ok2);
00359         if(qvApp->isRunning())
00360                 {
00361                 qvp_err = this;
00362                 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1:"
00363                                         "Cannot link properties after launching QVApplication.\n")
00364                                         .arg(prop_orig).arg(this->getName());
00365                 }
00366         else if(this == qvp_dest)
00367                 {
00368                 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1: cannot link a QVPropertyContainer with itself.\n").arg(this->getName());
00369                 qvp_err = this;
00370                 }
00371         else if(not ok1)
00372                 {
00373                 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00374                                 .arg(prop_orig).arg(this->getName());
00375                 qvp_err = this;
00376                 }
00377         else if (not ok2)
00378                 {
00379                 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00380                                 .arg(prop_dest).arg(qvp_dest->getName());
00381                 qvp_err = qvp_dest;
00382                 }
00383         else if(t1 != t2)
00384                 {
00385                 errMsg = QString("QVPropertyContainer::linkProperty(): Properties %1 and %2 of QVPropertyContainers %3 and %4 respectively are not of the same type.\n").arg(prop_orig).arg(prop_dest).arg(this->getName()).arg(qvp_dest->getName());
00386                 qvp_err = this;
00387                 }
00388         else if(not (this->io_flags[prop_orig] & outputFlag))
00389                 {
00390                 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 of property holder %2 is not of Output type, and cannot be linked as such.\n").arg(prop_orig).arg(this->getName());
00391                 qvp_err = this;
00392                 }
00393         else if(not (qvp_dest->io_flags[prop_dest] & inputFlag))
00394                 {
00395                 errMsg = QString("QVPropertyContainer::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());
00396                 qvp_err = qvp_dest;
00397                 }
00398 
00399         if(errMsg != QString())
00400                 {
00401                 qvp_err->setLastError(errMsg);
00402                 if(qvApp->isRunning()) {
00403                         std::cerr << qPrintable("Warning: " + errMsg + "\n");
00404                 } // Otherwise, qApp will show the error and won't start the program.
00405                 return FALSE;
00406                 }
00407         else
00408                 {
00409                 QVPropertyContainerLink *link = new QVPropertyContainerLink(this,prop_orig,qvp_dest,prop_dest,link_type);
00410                 this->outputLinks[prop_orig].push_back(link);
00411                 this->link_flags[prop_orig] |= linkedOutputFlag;
00412                 // We add a new metod "addInputLink(prop_dest, link);" instead of
00413                 // do: "qvp_dest->inputLinks[prop_dest] = link; qvp_dest->link_flags[prop_dest] |= linkedInputFlag;", in order to
00414                 // qvp_dest can emit a signal saying that its links were changed
00415                 qvp_dest->addInputLink(prop_dest, link);
00416 
00417                 // Now, we initialize the shared state, simply protected by the
00418                 // corresponding RWLock:
00419                 this->RWLock.lockForWrite();
00420                 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00421                 this->RWLock.unlock();
00422 
00423                 if (link_type == QVPropertyContainer::AsynchronousLink)
00424                         informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::LinkAdd, this->getName(), prop_orig, qvp_dest->getName(), prop_dest,FALSE));
00425                 else
00426                         informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::LinkAdd, this->getName(), prop_orig, qvp_dest->getName(), prop_dest,TRUE));
00427                 return TRUE;
00428                 }
00429         }
00430 
00431 void QVPropertyContainer::addInputLink(QString prop_dest, QVPropertyContainerLink *link)
00432         {
00433                 inputLinks[prop_dest] = link;
00434                 link_flags[prop_dest] |= linkedInputFlag;
00435         }
00436 
00437 void QVPropertyContainer::linkProperty(QVPropertyContainer *container, LinkType linkType)
00438         {
00439         QList<QString> localProper = getPropertyList();
00440         QList<QString> inputProper = container->getPropertyList();
00441 
00442         qSort(localProper.begin(), localProper.end());
00443         qSort(inputProper.begin(), inputProper.end());
00444 
00445         int i=0, l=0;
00446         while ( (i < inputProper.size()) && (l < localProper.size()) )
00447                 {
00448                 QString localName = localProper[l];
00449                 QString inputName = inputProper[i];
00450                 if (
00451                         (localName == inputName) && // si tienen el mismo nombre
00452                         (getPropertyType(localName) == container->getPropertyType(inputName)) && // si tienen el mismo tipo
00453                         (io_flags[localName] & outputFlag) && // si una es de entrada
00454                         (container->io_flags[inputName] & inputFlag) && // y otra de salida
00455                         (!(io_flags[localName] & internalProp)) && // y no son propiedades internas
00456                         (!(container->io_flags[inputName] & internalProp))
00457                    )
00458                         linkProperty(localProper[l], container, inputProper[i], linkType);
00459 
00460                 if(localName <= inputName) l++;
00461                 if(localName >= inputName) i++;
00462                 }
00463         }
00464 
00465 bool QVPropertyContainer::unlinkProperty(QString origName, QVPropertyContainer *destCont, QString destName)
00466         {
00467                 QList<QVPropertyContainerLink*> linkList = outputLinks[origName];
00468                 foreach(QVPropertyContainerLink* link, linkList) {
00469                         if ( (link->qvp_orig == this) && (link->prop_orig == origName) &&
00470                                 (link->qvp_dest == destCont) && (link->prop_dest == destName) ) {
00471                                 link->markedForDeletion = TRUE;
00472                                 // Protect against a possible pending acquire() for our output
00473                                 // in other holders:
00474                                 link->SyncSemaphoreOut.release();
00475                                 informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::LinkDel, this->getName(), origName, destCont->getName(), destName));
00476                                 return TRUE;
00477                         }
00478                 }
00479                 return FALSE;
00480         }
00481 
00482 void QVPropertyContainer::unlink()
00483 {
00484         foreach(QVPropertyContainerLink* link, inputLinks.values()) {
00485                 link->markedForDeletion = TRUE;
00486                 // Protect against a possible pending acquire() from our input
00487                 // in other holders:
00488                 link->SyncSemaphoreIn.release();
00489                 // using the orig and dest names because references should be bads if we are unlink all the items
00490                 informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::LinkDel, link->qvp_orig_name, link->prop_orig, link->qvp_dest_name, link->prop_dest));
00491         }
00492 
00493         foreach(QList<QVPropertyContainerLink*> linkList, outputLinks.values()) {
00494                 foreach(QVPropertyContainerLink* link, linkList) {
00495                         link->markedForDeletion = TRUE;
00496                         // Protect against a possible pending acquire() for our output
00497                         // in other holders:
00498                         link->SyncSemaphoreOut.release();
00499                         // using the orig and dest names because references should be bads if we are unlink all the items
00500                         informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::LinkDel, link->qvp_orig_name, link->prop_orig, link->qvp_dest_name, link->prop_dest));
00501                 }
00502         }
00503 }
00504 
00505 void QVPropertyContainer::readInputProperties()
00506         {
00507         // We read every linked input property from its source, protecting
00508         // the read with a standard RWLock (that here we just lock for read).
00509         // The only caveat is that if a property is synchronously read, then
00510         // we must wait for the producer to write it first. We implement that
00511         // by waiting on the SyncSemaphoreOut of the link. Also, in this
00512         // case when we finish reading the property, we signal every possible
00513         // waiting writer that, regarding this specific link, it can write now
00514         // a new value if it needs to, because we have read the old value yet.
00515         // This is implemented by releasing the SyncSemaphoreIn associated to
00516         // the link.
00517         QMutableMapIterator<QString, QVPropertyContainerLink*> i(inputLinks);
00518         while (i.hasNext()) {
00519                 i.next();
00520                 QVPropertyContainerLink *link = i.value();
00521                 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00522                         link->SyncSemaphoreOut.acquire();
00523                 }
00524                 link->qvp_orig->RWLock.lockForRead();
00525                 //this->setPropertyValueQVariant(link->prop_dest,link->qvp_orig->safelyCopiedVariants[link->prop_orig]);
00526                 this->variants[link->prop_dest] = link->qvp_orig->safelyCopiedVariants[link->prop_orig];
00527                 link->qvp_orig->RWLock.unlock();
00528                 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00529                         link->SyncSemaphoreIn.release();
00530                 }
00531                 informer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::PropertyValue, link->prop_dest));
00532                 // Possible link deletion:
00533                 if(link->markedForDeletion) {
00534                         i.remove();
00535                         toDeleteLink(link);
00536                 }
00537         }
00538 }
00539 
00540 void QVPropertyContainer::writeOutputProperties()
00541         {
00542         QMutableMapIterator<QString, QList<QVPropertyContainerLink*> >i(outputLinks);
00543 
00544         // For every QVP synchronously linked to this QVP's output, we ask
00545         // for permision to write a new output (that will only be possible if
00546         // all of these QVP's have read their inputs already):
00547         while (i.hasNext()) {
00548                 i.next();
00549                 QListIterator<QVPropertyContainerLink*> j(i.value());
00550                 while(j.hasNext()) {
00551                         QVPropertyContainerLink *link = j.next();
00552                         if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00553                                 link->SyncSemaphoreIn.acquire();
00554                         }
00555                 }
00556         }
00557 
00558         // Now, we write a new coherent state, simply protected by the
00559         // corresponding RWLock:
00560         i.toFront();
00561         this->RWLock.lockForWrite();
00562         while (i.hasNext()) {
00563                 i.next();
00564                 QString prop_orig = i.key();
00565                 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00566         }
00567         this->RWLock.unlock();
00568 
00569         // Finally, we signal to QVP's synchronously linked to this QVP's output
00570         // that there is a new coherent output, by releasing the corresponding
00571         // semaphore.
00572         i.toFront();
00573         while (i.hasNext()) {
00574                 i.next();
00575                 QMutableListIterator<QVPropertyContainerLink*> j(i.value());
00576                 while(j.hasNext()) {
00577                         QVPropertyContainerLink *link = j.next();
00578                         if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00579                                 link->SyncSemaphoreOut.release();
00580                         }
00581                         // Possible link deletion:
00582                         if(link->markedForDeletion) {
00583                                 j.remove();
00584                                 toDeleteLink(link);
00585                                 if(i.value().isEmpty()) {
00586                                         i.remove();
00587                                         break;
00588                                 }
00589                         }
00590                 }
00591         }
00592 }
00593 
00594 void QVPropertyContainer::toDeleteLink(QVPropertyContainerLink* link)
00595         {
00596                 if (link->qvp_orig == this) {
00597                         link->qvp_orig = NULL;
00598                 }
00599                 else if (link->qvp_dest == this) {
00600                         link->qvp_dest = NULL;
00601                 }
00602 
00603                 if ((link->qvp_orig == NULL) && (link->qvp_dest == NULL)) delete link;
00604         }
00605 
00606 void QVPropertyContainer::setLastError(QString str) const
00607         { errorString = str; }
00608 
00609 bool QVPropertyContainer::areSynchronized(const QList<QVPropertyContainer *> conts)
00610         {
00611         QVDisjointSet dSet(conts.size());
00612 
00613         for (int i = 0; i < conts.size(); i++)
00614                 for (int j = i+1; j < conts.size(); j++) // for each pair of container
00615                         {
00616                         bool find = false; // only need one syncrhonous property to be synchronized
00617 
00618                         if (conts.at(i)->getId() == conts.at(j)->getId()) // if they are the same container, they are synchronized
00619                                 {
00620                                 dSet.unify(i, j); // unify their sets
00621                                 find = true;
00622                                 }
00623                         if (!find)
00624                                 {
00625                                 const QMap<QString, QVPropertyContainerLink* > inLinksI = conts.at(i)->getInputLinks();
00626                                 foreach(QVPropertyContainerLink* proConLink, inLinksI.values())        // for each first container's linked input property
00627                                         if ( (proConLink->qvp_orig->getId() == conts.at(j)->getId()) &&   // if is linked from second container
00628                                              (proConLink->link_type == SynchronousLink)                ) // and is a synchronous link
00629                                                 {
00630                                                 dSet.unify(i, j); // unify their sets
00631                                                 find = true;
00632                                                 break;
00633                                                 }
00634                                 }
00635                         if (!find)
00636                                 {
00637                                 const QMap<QString, QVPropertyContainerLink* > inLinksJ = conts.at(j)->getInputLinks();
00638                                 foreach(QVPropertyContainerLink* proConLink, inLinksJ.values())        // for each second container's linked input property
00639                                         if ( (proConLink->qvp_orig->getId() == conts.at(i)->getId()) &&   // if is linked from first container
00640                                              (proConLink->link_type == SynchronousLink)                ) // and is a synchronous link
00641                                                 {
00642                                                 dSet.unify(i, j); // unify their sets
00643                                                 break;
00644                                                 }
00645                                 }
00646                         }
00647 
00648         return (dSet.numberOfSets() == 1);
00649         }
00650 
00651 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value)
00652         {
00653         if (value.toLower() == "true" || value.toLower() == "false")
00654                 {
00655                 //variants[parameter] = QVariant::fromValue<bool>(value.toLower() == "true");
00656                 setPropertyValue<bool>(parameter,value.toLower() == "true");
00657                 return TRUE;
00658                 }
00659         else {
00660                 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00661                                         ": value " + value +
00662                                         " is not a valid boolean value for parameter " +
00663                                         parameter + ".\n";
00664                 return FALSE;
00665                 }
00666         }
00667 
00668 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value)
00669         {
00670         bool okInt;
00671         int intValue = value.toInt(&okInt);
00672         if(not okInt)
00673                 {
00674                 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00675                                         ": value " + value +
00676                                         " is not a valid integer value for parameter " +
00677                                         parameter + ".\n";
00678                 return FALSE;
00679                 }
00680         //variants[parameter] = QVariant::fromValue<int>(intValue);
00681         setPropertyValue<int>(parameter,intValue);
00682         return TRUE;
00683         }
00684 
00685 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value)
00686         {
00687         bool okDouble;
00688         double doubleValue = value.toDouble(&okDouble);
00689         if(not okDouble)
00690                 {
00691                 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00692                                         ": value " + value +
00693                                         " is not a valid double value for parameter " +
00694                                         parameter + ".\n";
00695                 return FALSE;
00696                 }
00697         //variants[parameter] = QVariant::fromValue<double>(doubleValue);
00698         setPropertyValue<double>(parameter,doubleValue);
00699         return TRUE;
00700         }
00701 
00702 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value)
00703         {
00704         //variants[parameter] = QVariant::fromValue<QString>(value);
00705         setPropertyValue<QString>(parameter,value);
00706         return TRUE;
00707         }