PARP Research Group University of Murcia, Spain


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(), master(this), deepLevel(0)
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         slavesByLevel.append(QList<QVPropertyContainer *>());
00052         slavesByLevel[0].append(this);
00053         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ") <- return";
00054         }
00055 
00056 QVPropertyContainer::QVPropertyContainer(const QVPropertyContainer &cont):
00057         name(cont.name), ident(cont.ident), errorString(cont.errorString), variants(cont.variants),
00058         safelyCopiedVariants(cont.safelyCopiedVariants), minimum(cont.minimum), maximum(cont.maximum),
00059         _info(cont._info), io_flags(cont.io_flags), link_flags(cont.link_flags), insertion_order(cont.insertion_order),
00060         RWLock(), inputLinks(cont.inputLinks), outputLinks(cont.outputLinks), master(this), deepLevel(0)
00061         {
00062         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ")";
00063         if(qvApp == NULL)
00064                 {
00065                 QString str = "QVPropertyContainer::QVPropertyContainer(): holder " + name +
00066                                           ": property holders cannot be created before the " +
00067                                           "QVApplication instance. Aborting now.";
00068                 std::cerr << qPrintable(str) << std::endl;
00069                 exit(1);
00070                 }
00071         else
00072                 {
00073                 qvApp->registerQVPropertyContainer(this);
00074 //              QVPropertyContainer::globalInformer.emitChange(QVPropertyContainerChange(this, QVPropertyContainerChange::ContainerAdd));
00075                 }
00076         slavesByLevel.append(QList<QVPropertyContainer *>());
00077         slavesByLevel[0].append(this);
00078         qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ") <- return";
00079         }
00080 
00081 QVPropertyContainer & QVPropertyContainer::operator=(const QVPropertyContainer &cont)
00082         {
00083         name = cont.name;
00084         ident = cont.ident;
00085         errorString = cont.errorString;
00086         variants = cont.variants;
00087         safelyCopiedVariants = cont.safelyCopiedVariants;
00088         minimum = cont.minimum;
00089         maximum = cont.maximum;
00090         _info = cont._info;
00091         io_flags = cont.io_flags;
00092         link_flags = cont.link_flags;
00093         insertion_order = cont.insertion_order;
00094         inputLinks = cont.inputLinks;
00095         outputLinks = cont.outputLinks;
00096         master = this;
00097         deepLevel = 0;
00098 
00099         slavesByLevel.append(QList<QVPropertyContainer *>());
00100         slavesByLevel[0].append(this);
00101         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::All));
00102         return *this;
00103         }
00104 
00105 QVPropertyContainer::~QVPropertyContainer()
00106         {
00107         if(qvApp != NULL)
00108                 qvApp->deregisterQVPropertyContainer(this);
00109 
00110         unlink();
00111         readInputProperties();
00112         writeOutputProperties();
00113         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::ContainerDel));
00114         }
00115 
00116 void QVPropertyContainer::setName(const QString name)
00117         { this->name = name; informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::Name)); }
00118 
00119 const QString QVPropertyContainer::getName() const
00120         { return this->name; }
00121 
00122 const uint QVPropertyContainer::getId() const
00123         { return this->ident; }
00124 
00125 bool QVPropertyContainer::operator==(const QVPropertyContainer &cont) const
00126         { return (ident == cont.ident); }
00127 
00128 QList<QString> QVPropertyContainer::getPropertyList() const
00129         { return variants.keys(); }
00130 
00131 bool QVPropertyContainer::containsProperty(const QString name) const
00132         { return variants.contains(name); }
00133 
00134 int QVPropertyContainer::getPropertyType(const QString name, bool *ok) const
00135         {
00136         if(not checkExists(name,"QVPropertyContainer::getPropertyType()"))
00137                 {
00138                 if(ok != NULL) *ok = FALSE;
00139                 return QVariant::Invalid;
00140                 }
00141         if(ok != NULL) *ok = TRUE;
00142         QVariant variant = variants.value(name);
00143         return variant.userType();
00144         }
00145 
00146 bool QVPropertyContainer::removeProperty(const QString name)
00147         {
00148         if(not checkExists(name,"QVPropertyContainer::removeProperty()"))
00149                 return FALSE;
00150         this->variants.remove(name);
00151         this->safelyCopiedVariants.remove(name);
00152         this->minimum.remove(name);
00153         this->maximum.remove(name);
00154         this->_info.remove(name);
00155         this->io_flags.remove(name);
00156         int i = this->insertion_order.indexOf(name);
00157         this->insertion_order.removeAt(i);
00158         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::PropertyDel, name));
00159         return TRUE;
00160         }
00161 /*
00162 bool QVPropertyContainer::setPropertyRange(const QString name, const double & minimum, const double & maximum)
00163         {
00164         std::cerr << "WARNING: setPropertyRange() is deprecated. Specify range in the function addProperty instead." << std::endl;
00165         if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00166                 return FALSE;
00167         if(minimum <= getPropertyValue<double>(name) and
00168                 maximum >= getPropertyValue<double>(name))
00169                 {
00170                         this->minimum[name] = QVariant::fromValue(minimum);
00171                         this->maximum[name] = QVariant::fromValue(maximum);
00172                         return TRUE;
00173                 } else {
00174                         QString str =  "QVPropertyContainer::setPropertyRange(): property " +
00175                                                    name + " in holder " + getName() + " has value " +
00176                                                    QString("%1").arg(getPropertyValue<double>(name)) +
00177                                                    ", which is not valid for the range [" +
00178                                                    QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00179                         setLastError(str);
00180                         if(qvApp->isRunning()) {
00181                                 std::cerr << qPrintable("Warning: " + str + "\n");
00182                         } // Otherwise, qApp will show the error and won't start the program.
00183                         return FALSE;
00184                 }
00185         }
00186 
00187 bool QVPropertyContainer::setPropertyRange(QString name, int & minimum, int & maximum)
00188         { return setPropertyRange(name, static_cast<double>(minimum), static_cast<double>(maximum)); }
00189 */
00190 bool QVPropertyContainer::hasRange(const QString name) const
00191         { return maximum.contains(name) and minimum.contains(name); }
00192 
00193 bool QVPropertyContainer::isInput(const QString name) const
00194         { return (io_flags[name] & inputFlag);};
00195 
00196 bool QVPropertyContainer::isOutput(const QString name) const
00197         { return (io_flags[name] & outputFlag);};
00198 
00199 bool QVPropertyContainer::isGUIInvisible(const QString name) const
00200         { return (io_flags[name] & guiInvisible);};
00201 
00202 bool QVPropertyContainer::isLinkedInput(const QString name) const
00203         { return (link_flags[name] & linkedInputFlag);};
00204 
00205 bool QVPropertyContainer::isLinkedOutput(const QString name) const
00206         { return (link_flags[name] & linkedOutputFlag);};
00207 
00208 QVariant QVPropertyContainer::getPropertyQVariantValue(const QString name, bool *ok) const
00209         {
00210         if (not checkExists(name,"QVPropertyContainer::getPropertyQVariantValue()"))
00211                 if(ok != NULL) *ok = FALSE;
00212         else
00213                 if(ok != NULL) *ok = TRUE;
00214         return variants[name];
00215         }
00216 
00217 QString QVPropertyContainer::getPropertyInfo(const QString name, bool *ok) const
00218         {
00219         if(not checkExists(name,"QVPropertyContainer::getPropertyInfo()"))
00220                 if(ok != NULL) *ok = FALSE;
00221         else
00222                 if(ok != NULL) *ok = TRUE;
00223         return this->_info[name];
00224         }
00225 
00226 QString QVPropertyContainer::getLastError() const
00227         {
00228         return errorString;
00229         }
00230 
00231 const QString QVPropertyContainer::infoInputProperties() const
00232         {
00233         qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ")";
00234 
00235         QString info = QString("Input parameters for ") + getName() + QString(":\n");
00236         bool emptyInfo=TRUE;
00237 
00238         qDebug() << "QVPropertyContainer::infoInputProperties(): Properties " << insertion_order;
00239 
00240         foreach (QString property, insertion_order)
00241         //QListIterator<QString> i(insertion_order);
00242         //while (i.hasNext())
00243                 {
00244                 //const QString property = i.next();
00245 
00246                 if( not isInput(property) )
00247                         continue;
00248 
00249                 bool printableProperty = TRUE;
00250                 QString propertyInfo("  --" + property + "=");
00251 
00252                 switch(getPropertyType(property))
00253                         {
00254                         case QVariant::String:
00255                                 propertyInfo += QString() + "[text] " + "(def. '" + getPropertyValue<QString>(property) + "') ";
00256                                 break;
00257 
00258                         case QVariant::Double:
00259                                 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00260                                         "[" + QString().setNum(getPropertyMinimum<double>(property)) + "..."
00261                                                 + QString().setNum(getPropertyMaximum<double>(property)) + "] ":
00262                                         "[double] " ) + "(def. "+ QString().setNum(getPropertyValue<double>(property)) + ") ";
00263                                 break;
00264 
00265                         case QVariant::Int:
00266                                 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00267                                         "[" + QString().setNum(getPropertyMinimum<int>(property)) + "..." +
00268                                                 QString().setNum(getPropertyMaximum<int>(property)) + "] ":
00269                                         "[int] " ) + "(def. "+ QString().setNum(getPropertyValue<int>(property)) + ") ";
00270                                 break;
00271 
00272                         case QVariant::Bool:
00273                                 propertyInfo += "[true,false]" + (getPropertyValue<bool>(property) ?
00274                                                                 QString(" (def. true) "):QString("(def. false) "));
00275                                 break;
00276 
00277                         default:
00278                                 printableProperty = FALSE;
00279                                 break;
00280                         }
00281 
00282                 if (printableProperty)
00283                         {
00284                         info += propertyInfo + getPropertyInfo(property).rightJustified(100-propertyInfo.split('\n').last().length(),' ') + ".\n";
00285                         emptyInfo=FALSE;
00286                         }
00287                 }
00288 
00289         qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ") <~ return";
00290 
00291         if(emptyInfo)
00292                 return QString("");
00293         
00294         return info;
00295         }
00296 
00297 bool QVPropertyContainer::correctRange(const QString name, const double & value) const
00298         {
00299         if(not maximum.contains(name) and not minimum.contains(name))
00300                 return TRUE;
00301         double maximum = getPropertyMaximum<double>(name);
00302         double minimum = getPropertyMinimum<double>(name);
00303         if(minimum <= value and maximum >= value)
00304                 return TRUE;
00305         else
00306                 {
00307                 QString str =  "QVPropertyContainer::setPropertyValue(): value " +
00308                                            QString("%1").arg(value) + " for property " +
00309                                            name + " in holder " + getName() +
00310                                            "is not valid for the range [" +
00311                                            QString("%1,%2").arg(minimum).arg(maximum) + 
00312                                            "] stablished for it." ;
00313                 setLastError(str);
00314                 if(qvApp->isRunning())
00315                         {
00316                         std::cerr << qPrintable("Warning: " + str + "\n");
00317                         } // Otherwise, qApp will show the error and won't start the program.
00318                 return FALSE;
00319                 }
00320         }
00321 
00322 bool QVPropertyContainer::correctRange(const char *name, const int & value) const
00323         { return correctRange(QString(name),static_cast<double>(value)); }
00324 
00325 bool QVPropertyContainer::correctRange(QString name, const int & value) const
00326         { return correctRange(name,static_cast<double>(value)); }
00327 
00328 bool QVPropertyContainer::checkExists(const QString name, const QString methodname) const
00329         {
00330         if(not variants.contains(name))
00331                 {
00332                 QString str =  methodname + ": property " + name +
00333                                            " doesn't exists in holder " + getName() + ".";
00334                 setLastError(str);
00335                 if(qvApp->isRunning()) {
00336                         std::cerr << qPrintable("Warning: " + str + "\n");
00337                 } // Otherwise, qApp will show the error and won't start the program.
00338                 return FALSE;
00339                 } else {
00340                 return TRUE;
00341                 }
00342         }
00343 
00344 bool QVPropertyContainer::checkIsNewProperty(const QString name, const QString methodname) const
00345         {
00346         if(variants.contains(name))
00347                 {
00348                 QString str =  methodname + "(): property " + name +
00349                                            " already exists in holder " + getName() + ".";
00350                 setLastError(str);
00351                 if(qvApp->isRunning()) {
00352                         std::cerr << qPrintable("Warning: " + str + "\n");
00353                 } // Otherwise, qApp will show the error and won't start the program.
00354                 return FALSE;
00355                 } else {
00356                 return TRUE;
00357                 }
00358         }
00359 
00361 
00362 bool QVPropertyContainer::linkProperty(QString prop_orig, QVPropertyContainer *qvp_dest, QString prop_dest, LinkType link_type)
00363         {
00364         bool ok1,ok2;
00365         QString errMsg;
00366         int t1,t2;
00367         QVPropertyContainer *qvp_err=NULL;
00368         
00369         t1 = this->getPropertyType(prop_orig,&ok1);
00370         t2 = qvp_dest->getPropertyType(prop_dest,&ok2);
00371         if(qvApp->isRunning())
00372                 {
00373                 qvp_err = this;
00374                 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1:"
00375                                         "Cannot link properties after launching QVApplication.\n")
00376                                         .arg(prop_orig).arg(this->getName());
00377                 }
00378         else if(this == qvp_dest)
00379                 {
00380                 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1: cannot link a QVPropertyContainer with itself.\n").arg(this->getName());
00381                 qvp_err = this;
00382                 }
00383         else if(not ok1)
00384                 {
00385                 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00386                                 .arg(prop_orig).arg(this->getName());
00387                 qvp_err = this;
00388                 }
00389         else if (not ok2)
00390                 {
00391                 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00392                                 .arg(prop_dest).arg(qvp_dest->getName());
00393                 qvp_err = qvp_dest;
00394                 }
00395         else if(t1 != t2)
00396                 {
00397                 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());
00398                 qvp_err = this;
00399                 }
00400         else if(not (this->io_flags[prop_orig] & outputFlag))
00401                 {
00402                 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());
00403                 qvp_err = this;
00404                 }
00405         else if(not (qvp_dest->io_flags[prop_dest] & inputFlag))
00406                 {
00407                 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());
00408                 qvp_err = qvp_dest;
00409                 }
00410         else if( (link_type == SequentialLink) && (!ProcessPosibleSequentialLink(qvp_dest)) )
00411                 {
00412                 errMsg = QString("QVPropertyContainer::linkProperty(): A new link cannot generate a cycle of SequentialLinks.\n");
00413                 qvp_err = this;
00414                 }
00415 
00416         if(errMsg != QString())
00417                 {
00418                 qvp_err->setLastError(errMsg);
00419                 if(qvApp->isRunning()) {
00420                         std::cerr << qPrintable("Warning: " + errMsg + "\n");
00421                 } // Otherwise, qApp will show the error and won't start the program.
00422                 return FALSE;
00423                 }
00424         else
00425                 {
00426                 QVPropertyContainerLink *link = new QVPropertyContainerLink(this,prop_orig,qvp_dest,prop_dest,link_type);
00427                 this->outputLinks[prop_orig].push_back(link);
00428                 this->link_flags[prop_orig] |= linkedOutputFlag;
00429                 // We add a new method "addInputLink(prop_dest, link);" instead of doing
00430                 // "qvp_dest->inputLinks[prop_dest] = link; qvp_dest->link_flags[prop_dest] |= linkedInputFlag;", for
00431                 // qvp_dest to emit a signal saying that its links were changed.
00432                 qvp_dest->addInputLink(prop_dest, link);
00433 
00434                 // Now, we initialize the shared state, simply protected by the
00435                 // corresponding RWLock:
00436                 this->RWLock.lockForWrite();
00437                 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00438                 this->RWLock.unlock();
00439 
00440                 if (link_type == QVPropertyContainer::AsynchronousLink)
00441                         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::LinkAdd, this->getName(), prop_orig, qvp_dest->getName(), prop_dest,FALSE,FALSE));
00442                 else if (link_type == QVPropertyContainer::SynchronousLink)
00443                         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::LinkAdd, this->getName(), prop_orig, qvp_dest->getName(), prop_dest,TRUE, FALSE));
00444                 else
00445                         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::LinkAdd, this->getName(), prop_orig, qvp_dest->getName(), prop_dest,FALSE, TRUE));
00446 
00447                 return TRUE;
00448                 }
00449         }
00450 
00451 bool QVPropertyContainer::linkProperty(QVPropertyContainer *destinyContainer, QString destinyPropertyName, LinkType linkType)
00452         {
00453         if (linkUnspecifiedOutputProperty(destinyContainer, destinyPropertyName, linkType))
00454                 return true;
00455         else    {
00456                 std::cerr << "ERROR: QVPropertyContainer::linkProperty(): source container " << qPrintable(getName()) << " can't handle unspecified output properties linking" << std::endl;
00457                 return false;
00458                 }
00459         }
00460 
00461 bool QVPropertyContainer::linkProperty(QString sourcePropertyName, QVPropertyContainer *destinyContainer, LinkType linkType)
00462         {
00463         if (destinyContainer->linkUnspecifiedInputProperty(this, sourcePropertyName, linkType))
00464                 return true;
00465         else    {
00466                 std::cerr << "ERROR: QVPropertyContainer::linkProperty(): destination container " << qPrintable(destinyContainer->getName()) << " can't handle unspecified input properties linking" << std::endl;
00467                 return false;
00468                 }
00469         }
00470 
00471 void QVPropertyContainer::linkProperty(QVPropertyContainer *container, LinkType linkType)
00472         {
00473         QList<QString> localProper = getPropertyList();
00474         QList<QString> inputProper = container->getPropertyList();
00475 
00476         qSort(localProper.begin(), localProper.end());
00477         qSort(inputProper.begin(), inputProper.end());
00478 
00479         int i=0, l=0;
00480         while ( (i < inputProper.size()) && (l < localProper.size()) )
00481                 {
00482                 QString localName = localProper[l];
00483                 QString inputName = inputProper[i];
00484                 if (
00485                         (localName == inputName) && // si tienen el mismo nombre
00486                         (getPropertyType(localName) == container->getPropertyType(inputName)) && // si tienen el mismo tipo
00487                         (io_flags[localName] & outputFlag) && // si una es de entrada
00488                         (container->io_flags[inputName] & inputFlag) && // y otra de salida
00489                         (!(io_flags[localName] & internalProp)) && // y no son propiedades internas
00490                         (!(container->io_flags[inputName] & internalProp))
00491                    )
00492                         linkProperty(localProper[l], container, inputProper[i], linkType);
00493 
00494                 if(localName <= inputName) l++;
00495                 if(localName >= inputName) i++;
00496                 }
00497         }
00498 
00500 
00501 bool QVPropertyContainer::linkProperty(QString prop_orig, QVPropertyContainer &qvp_dest, QString prop_dest, LinkType link_type)
00502         {
00503         return linkProperty(prop_orig, &qvp_dest, prop_dest, link_type);
00504         }
00505 
00506 bool QVPropertyContainer::linkProperty(QVPropertyContainer &destinyContainer, QString destinyPropertyName, LinkType linkType)
00507         {
00508         return linkProperty(&destinyContainer, destinyPropertyName, linkType);
00509         }
00510 
00511 bool QVPropertyContainer::linkProperty(QString sourcePropertyName, QVPropertyContainer &destinyContainer, LinkType linkType)
00512         {
00513         return linkProperty(sourcePropertyName, &destinyContainer, linkType);
00514         }
00515 
00516 void QVPropertyContainer::linkProperty(QVPropertyContainer &container, LinkType linkType)
00517         {
00518         linkProperty(&container, linkType);
00519         }
00520 
00522 
00523 bool QVPropertyContainer::linkUnspecifiedInputProperty(QVPropertyContainer *srcCont, QString srcProp, LinkType linkType)
00524         {
00525         if (containsProperty(srcProp))
00526                 return srcCont->linkProperty(srcProp, this, srcProp, linkType);
00527         else
00528                 return false;
00529         }
00530 
00531 bool QVPropertyContainer::linkUnspecifiedOutputProperty(QVPropertyContainer *dstCont, QString dstProp, LinkType linkType)
00532         {
00533         if (containsProperty(dstProp))
00534                 return linkProperty(dstProp, dstCont, dstProp, linkType);
00535         else
00536                 return false;
00537         }
00538 
00540 
00541 void QVPropertyContainer::addInputLink(QString prop_dest, QVPropertyContainerLink *link)
00542         {
00543         inputLinks[prop_dest] = link;
00544         link_flags[prop_dest] |= linkedInputFlag;
00545         }
00546 
00547 bool QVPropertyContainer::unlinkProperty(QString origName, QVPropertyContainer *destCont, QString destName)
00548         {
00549         QList<QVPropertyContainerLink*> linkList = outputLinks[origName];
00550         foreach(QVPropertyContainerLink* link, linkList) {
00551                 if ( (link->qvp_orig == this) && (link->prop_orig == origName) &&
00552                         (link->qvp_dest == destCont) && (link->prop_dest == destName) ) {
00553                         bool isSequential = (link->link_type == SequentialLink);
00554                         link->markedForDeletion = TRUE;
00555                         // Protect against a possible pending acquire() for our output
00556                         // in other holders:
00557                         link->SyncSemaphoreOut.release();
00558                         destCont->treatUnlinkInputProperty(destName, this, origName);
00559                         // This ProcessSequentialUnlink cannot generate a core for acceding to all group nodes
00560                         // because the two QVPropertyContainer's are in the same thread and its unlinks
00561                         // are doing sequentialy
00562                         if ( (isSequential) && (link->qvp_dest != NULL) ) ProcessSequentialUnlink(destCont);
00563                         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::LinkDel, this->getName(), origName, destCont->getName(), destName));
00564                         return TRUE;
00565                 }
00566         }
00567         return FALSE;
00568         }
00569 
00570 bool QVPropertyContainer::unlinkProperty(QString origName, QVPropertyContainer &destCont, QString destName)
00571         {
00572         return unlinkProperty(origName, &destCont, destName);
00573         }
00574 
00575 bool QVPropertyContainer::treatUnlinkInputProperty(QString, QVPropertyContainer *, QString)
00576         {
00577         return true;
00578         }
00579 
00580 void QVPropertyContainer::unlink()
00581 {
00582         foreach(QVPropertyContainerLink* link, inputLinks.values()) {
00583                 bool isSequential = (link->link_type == SequentialLink);
00584                 link->markedForDeletion = TRUE;
00585                 // Protect against a possible pending acquire() from our input
00586                 // in other holders:
00587                 link->SyncSemaphoreIn.release();
00588                 // This ProcessSequentialUnlink cannot generate a core for acceding to all group nodes
00589                 // because the two QVPropertyContainer's are in the same thread and its unlinks
00590                 // are doing sequentialy
00591                 if ( (isSequential) && (link->qvp_dest != NULL) ) ProcessSequentialUnlink(link->qvp_dest);
00592                 informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::LinkDel, link->qvp_orig_name, link->prop_orig, link->qvp_dest_name, link->prop_dest));
00593         }
00594 
00595         foreach(QList<QVPropertyContainerLink*> linkList, outputLinks.values()) {
00596                 foreach(QVPropertyContainerLink* link, linkList) {
00597                         bool isSequential = (link->link_type == SequentialLink);
00598                         link->markedForDeletion = TRUE;
00599                         // Protect against a possible pending acquire() for our output
00600                         // in other holders:
00601                         link->SyncSemaphoreOut.release();
00602                         if (link->qvp_dest != NULL) link->qvp_dest->treatUnlinkInputProperty(link->prop_dest, this, link->prop_orig);
00603                         // This ProcessSequentialUnlink cannot generate a core for acceding to all group nodes
00604                         // because the two QVPropertyContainer's are in the same thread and its unlinks
00605                         // are doing sequentialy
00606                         if ( (isSequential) && (link->qvp_dest != NULL) ) ProcessSequentialUnlink(link->qvp_dest);
00607                         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::LinkDel, link->qvp_orig_name, link->prop_orig, link->qvp_dest_name, link->prop_dest));
00608                 }
00609         }
00610 }
00611 
00612 void QVPropertyContainer::readInputProperties()
00613         {
00614         // We read every linked input property from its source, protecting
00615         // the read with a standard RWLock (that here we just lock for read).
00616         // The only caveat is that if a property is synchronously read, then
00617         // we must wait for the producer to write it first. We implement that
00618         // by waiting on the SyncSemaphoreOut of the link. Also, in this
00619         // case when we finish reading the property, we signal every possible
00620         // waiting writer that, regarding this specific link, it can write now
00621         // a new value if it needs to, because we have read the old value yet.
00622         // This is implemented by releasing the SyncSemaphoreIn associated to
00623         // the link.
00624         QMutableMapIterator<QString, QVPropertyContainerLink*> i(inputLinks);
00625         while (i.hasNext()) {
00626                 i.next();
00627                 QVPropertyContainerLink *link = i.value();
00628 
00629                 // Possible link deletion:
00630                 if(link->markedForDeletion) {
00631                         i.remove();
00632                         toDeleteLink(link);
00633                 }
00634                 else {
00635                         if(link->link_type == SynchronousLink) {
00636                                 link->SyncSemaphoreOut.acquire();
00637                         }
00638                         if (link->link_type != SequentialLink)
00639                                 link->qvp_orig->RWLock.lockForRead();
00640                         //this->setPropertyValueQVariant(link->prop_dest,link->qvp_orig->safelyCopiedVariants[link->prop_orig]);
00641                         this->variants[link->prop_dest] = link->qvp_orig->safelyCopiedVariants[link->prop_orig];
00642                         if (link->link_type != SequentialLink)
00643                                 link->qvp_orig->RWLock.unlock();
00644                         if(link->link_type == SynchronousLink) {
00645                                 link->SyncSemaphoreIn.release();
00646                         }
00647                 }
00648         }
00649         informer.emitChange(QVPropertyContainerChange(this->getName(), QVPropertyContainerChange::PropertiesValues));
00650 }
00651 
00652 void QVPropertyContainer::writeOutputProperties()
00653         {
00654         QMutableMapIterator<QString, QList<QVPropertyContainerLink*> >i(outputLinks);
00655 
00656         // For every QVP synchronously linked to this QVP's output, we ask
00657         // for permision to write a new output (that will only be possible if
00658         // all of these QVP's have read their inputs already):
00659         bool someSequential = false;
00660         while (i.hasNext()) {
00661                 i.next();
00662                 QListIterator<QVPropertyContainerLink*> j(i.value());
00663                 while(j.hasNext()) {
00664                         QVPropertyContainerLink *link = j.next();
00665                         if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00666                                 link->SyncSemaphoreIn.acquire();
00667                         }
00668                         else if(link->link_type == SequentialLink and not link->markedForDeletion) {
00669                                 someSequential = true;
00670                         }
00671                 }
00672         }
00673 
00674         // Now, we write a new coherent state, simply protected by the
00675         // corresponding RWLock:
00676         i.toFront();
00677         if (!someSequential)
00678                 this->RWLock.lockForWrite();
00679         while (i.hasNext()) {
00680                 i.next();
00681                 QString prop_orig = i.key();
00682                 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00683         }
00684         if (!someSequential)
00685                 this->RWLock.unlock();
00686 
00687         // Finally, we signal to QVP's synchronously linked to this QVP's output
00688         // that there is a new coherent output, by releasing the corresponding
00689         // semaphore.
00690         i.toFront();
00691         while (i.hasNext()) {
00692                 i.next();
00693                 QMutableListIterator<QVPropertyContainerLink*> j(i.value());
00694                 while(j.hasNext()) {
00695                         QVPropertyContainerLink *link = j.next();
00696                         if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00697                                 link->SyncSemaphoreOut.release();
00698                         }
00699                         // Possible link deletion:
00700                         if(link->markedForDeletion) {
00701                                 j.remove();
00702                                 toDeleteLink(link);
00703                                 if(i.value().isEmpty()) {
00704                                         i.remove();
00705                                         break;
00706                                 }
00707                         }
00708                 }
00709         }
00710 }
00711 
00712 void QVPropertyContainer::toDeleteLink(QVPropertyContainerLink* link)
00713         {
00714                 if (link->qvp_orig == this) {
00715                         link->qvp_orig = NULL;
00716                 }
00717                 else if (link->qvp_dest == this) {
00718                         link->qvp_dest = NULL;
00719                 }
00720 
00721                 if ((link->qvp_orig == NULL) && (link->qvp_dest == NULL)) delete link;
00722         }
00723 
00724 void QVPropertyContainer::setLastError(QString str) const
00725         { errorString = str; }
00726 
00727 QVPropertyContainer *QVPropertyContainer::getSourceContainer(const QString name) const
00728         {
00729                 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00730                 if (inLinks.contains(name))
00731                         return inLinks.value(name)->qvp_orig;
00732 
00733                 return NULL;
00734         }
00735 
00736 QList<QVPropertyContainer *> QVPropertyContainer::getDestinyContainers(const QString name) const
00737         {
00738                 QList<QVPropertyContainer *> list;
00739 
00740                 if (outputLinks.contains(name))
00741                         foreach(QVPropertyContainerLink* link, outputLinks.value(name))
00742                                 if ( (link->qvp_dest != NULL) && (!list.contains(link->qvp_dest)) ) list.append(link->qvp_dest);
00743 
00744                 return list;
00745         }
00746 
00747 QString QVPropertyContainer::getSourceProperty(const QString name) const
00748         {
00749                 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00750                 if (inLinks.contains(name))
00751                         return inLinks.value(name)->prop_orig;
00752 
00753                 return QString();
00754         }
00755 
00756 bool QVPropertyContainer::isSynchronous(const QString name) const
00757         {
00758                 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00759                 if (inLinks.contains(name))
00760                         return (inLinks.value(name)->link_type == SynchronousLink);
00761 
00762                 return FALSE;
00763         }
00764 
00765 bool QVPropertyContainer::isSequential(const QString name) const
00766         {
00767                 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00768                 if (inLinks.contains(name))
00769                         return (inLinks.value(name)->link_type == SequentialLink);
00770 
00771                 return FALSE;
00772         }
00773 
00774 bool QVPropertyContainer::areSynchronized(const QList<QVPropertyContainer *> conts)
00775         {
00776         QVDisjointSet dSet(conts.size());
00777 
00778         for (int i = 0; i < conts.size(); i++)
00779                 for (int j = i+1; j < conts.size(); j++) // for each pair of container
00780                         {
00781                         bool find = false; // only need one syncrhonous property to be synchronized
00782 
00783                         if (conts.at(i)->getId() == conts.at(j)->getId()) // if they are the same container, they are synchronized
00784                                 {
00785                                 dSet.unify(i, j); // unify their sets
00786                                 find = true;
00787                                 }
00788                         if (!find)
00789                                 {
00790                                 const QMap<QString, QVPropertyContainerLink* > inLinksI = conts.at(i)->getInputLinks();
00791                                 foreach(QVPropertyContainerLink* proConLink, inLinksI.values())        // for each first container's linked input property
00792                                         if ( (proConLink->qvp_orig->getId() == conts.at(j)->getId()) &&   // if is linked from second container
00793                                              (proConLink->link_type != AsynchronousLink)               ) // and is a synchronous link
00794                                                 {
00795                                                 dSet.unify(i, j); // unify their sets
00796                                                 find = true;
00797                                                 break;
00798                                                 }
00799                                 }
00800                         if (!find)
00801                                 {
00802                                 const QMap<QString, QVPropertyContainerLink* > inLinksJ = conts.at(j)->getInputLinks();
00803                                 foreach(QVPropertyContainerLink* proConLink, inLinksJ.values())        // for each second container's linked input property
00804                                         if ( (proConLink->qvp_orig->getId() == conts.at(i)->getId()) &&   // if is linked from first container
00805                                              (proConLink->link_type != AsynchronousLink)               ) // and is a synchronous link
00806                                                 {
00807                                                 dSet.unify(i, j); // unify their sets
00808                                                 break;
00809                                                 }
00810                                 }
00811                         }
00812 
00813         return (dSet.numberOfSets() == 1);
00814         }
00815 
00816 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value)
00817         {
00818         if (value.toLower() == "true" || value.toLower() == "false")
00819                 {
00820                 //variants[parameter] = QVariant::fromValue<bool>(value.toLower() == "true");
00821                 setPropertyValue<bool>(parameter,value.toLower() == "true");
00822                 return TRUE;
00823                 }
00824         else {
00825                 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00826                                         ": value " + value +
00827                                         " is not a valid boolean value for parameter " +
00828                                         parameter + ".\n";
00829                 return FALSE;
00830                 }
00831         }
00832 
00833 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value)
00834         {
00835         bool okInt;
00836         int intValue = value.toInt(&okInt);
00837         if(not okInt)
00838                 {
00839                 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00840                                         ": value " + value +
00841                                         " is not a valid integer value for parameter " +
00842                                         parameter + ".\n";
00843                 return FALSE;
00844                 }
00845         //variants[parameter] = QVariant::fromValue<int>(intValue);
00846         setPropertyValue<int>(parameter,intValue);
00847         return TRUE;
00848         }
00849 
00850 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value)
00851         {
00852         bool okDouble;
00853         double doubleValue = value.toDouble(&okDouble);
00854         if(not okDouble)
00855                 {
00856                 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00857                                         ": value " + value +
00858                                         " is not a valid double value for parameter " +
00859                                         parameter + ".\n";
00860                 return FALSE;
00861                 }
00862         //variants[parameter] = QVariant::fromValue<double>(doubleValue);
00863         setPropertyValue<double>(parameter,doubleValue);
00864         return TRUE;
00865         }
00866 
00867 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value)
00868         {
00869         //variants[parameter] = QVariant::fromValue<QString>(value);
00870         setPropertyValue<QString>(parameter,value);
00871         return TRUE;
00872         }
00873 
00874 // the sequential subgraphs cannot have cicles
00875 bool QVPropertyContainer::ProcessPosibleSequentialLink(QVPropertyContainer *destCont)
00876         {
00877                 // Return false if the link will generate a sequential links cicle
00878                 if (haveSyncPrecursor(destCont))
00879                         return false;
00880 
00881                 // If they are sequentiely connected yet, do nothing
00882                 if (destCont->haveSyncPrecursor(this))
00883                         return true;
00884 
00885                 // Update de deeps
00886                 destCont->updateDeep(deepLevel);
00887 
00888                 // choose the new master of the join group
00889                 QVPropertyContainer *winnerMaster, *loserMaster;
00890                 if (this->master->getId() < destCont->master->getId()) {
00891                         winnerMaster = this->master;
00892                         loserMaster = destCont->master;
00893                 }
00894                 else {
00895                         winnerMaster = destCont->master;
00896                         loserMaster = this->master;
00897                 }
00898 
00899                 // change the masters of the group's items
00900                 for(int i = 0; i < loserMaster->slavesByLevel.size(); i++) {
00901                         if(winnerMaster->slavesByLevel.size() <= i)
00902                                 winnerMaster->slavesByLevel.append(QList<QVPropertyContainer *>());
00903 
00904                         QList<QVPropertyContainer *> level = loserMaster->slavesByLevel[i];
00905                         foreach(QVPropertyContainer *slave, level) {
00906                                 slave->master = winnerMaster;
00907                                 winnerMaster->slavesByLevel[i].append(slave);
00908                         }
00909                 }
00910 
00911                 // update the old master (looser master)
00912                 foreach(QList<QVPropertyContainer *> level, loserMaster->slavesByLevel) {
00913                         loserMaster->slavesByLevel.removeAll(level);
00914                 }
00915                 loserMaster->master = winnerMaster;
00916 
00917                 return true;
00918         }
00919 
00920 // the sequential subgraphs cannot have cicles
00921 void QVPropertyContainer::updateDeep(int origDeep)
00922          {
00923                 int newDeep = origDeep + 1; // sets its minim deep
00924                 foreach(QVPropertyContainerLink* inLink, getInputLinks()) { // calculate the new deep
00925                         QVPropertyContainer *cont = inLink->qvp_orig;
00926                         if ( (cont != NULL) && (inLink->markedForDeletion == FALSE) && (inLink->link_type == SequentialLink) )
00927                                 if (cont->deepLevel >= newDeep)
00928                                         newDeep = cont->deepLevel + 1;
00929                 }
00930 
00931                 if (newDeep != deepLevel) { // if the deep changes, change his level position, his deep, and his successors deep
00932                         master->slavesByLevel[deepLevel].removeAll(this);
00933                         deepLevel = newDeep;
00934         
00935                         while(master->slavesByLevel.size() <= deepLevel)
00936                                 master->slavesByLevel.append(QList<QVPropertyContainer *>());
00937                         master->slavesByLevel[deepLevel].append(this);
00938         
00939                         foreach(QString prop, getPropertyList())
00940                                 foreach(QVPropertyContainer *container, getDestinySequentialContainers(prop))
00941                                         container->updateDeep(deepLevel);
00942                 }
00943         }
00944 
00945 // the sequential subgraphs cannot have cicles
00946 void QVPropertyContainer::ProcessSequentialUnlink(QVPropertyContainer *destCont)
00947         {
00948                 // if the group still join do nothing
00949                 if (destCont->haveSyncPrecursor(this)) return;
00950 
00951                 // if it is in the masterless subgroup, they becomes a new master
00952                 if( (master != this) && !haveSyncPrecursor(master) && !master->haveSyncPrecursor(this) ) {
00953                         // changes all subgroup master
00954                         this->propagateBackwardMasterChange(this);
00955                         this->propagateForwardMasterChange(this);
00956                         this->changeMaster(this);
00957 
00958                         // update its (and its succesors) deep
00959                         this->updateDeep(-1);
00960 
00961                         // they must update other subgroup deep
00962                         destCont->updateDeep(-1);
00963                 }
00964                 // if destCont is in the masterless subgroup, they becomes a new master
00965                 else if( (master != destCont) && !destCont->haveSyncPrecursor(destCont->master) && !destCont->master->haveSyncPrecursor(destCont) ) {
00966                         // changes all subgroup master
00967                         destCont->propagateBackwardMasterChange(destCont);
00968                         destCont->propagateForwardMasterChange(destCont);
00969                         destCont->changeMaster(destCont);
00970 
00971                         // update its (and its succesors) deep
00972                         destCont->updateDeep(-1);
00973                 }
00974         }
00975 
00976 // the sequential subgraphs cannot have cicles
00977 bool QVPropertyContainer::haveSyncPrecursor(QVPropertyContainer *precursor)
00978         {
00979                 foreach(QString prop, getPropertyList()) {
00980                         if (/*isSynchronous(prop) || */isSequential(prop)) {
00981                                 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00982                                 QVPropertyContainer *cont = inLinks.value(prop)->qvp_orig;
00983                                 if ( (cont != NULL) && (inLinks.value(prop)->markedForDeletion == FALSE) )
00984                                         if ( (precursor == cont) || (cont->haveSyncPrecursor(precursor)) ) return true;
00985                         }
00986                 }
00987                 return false;
00988         }
00989 
00990 // the sequential subgraphs cannot have cicles
00991 void QVPropertyContainer::propagateBackwardMasterChange(QVPropertyContainer *newMaster)
00992         {
00993                 foreach(QVPropertyContainerLink *link, getInputLinks()) {
00994                         QVPropertyContainer *cont = link->qvp_orig;
00995                         if ( (cont != NULL) && (link->markedForDeletion == FALSE) && (link->link_type == SequentialLink) && (cont->master != newMaster) ) {
00996                                 cont->changeMaster(newMaster);
00997                                 cont->propagateBackwardMasterChange(newMaster);
00998                                 cont->propagateForwardMasterChange(newMaster);
00999                         }
01000                 }
01001 
01002         }
01003 
01004 // the sequential subgraphs cannot have cicles
01005 void QVPropertyContainer::propagateForwardMasterChange(QVPropertyContainer *newMaster)
01006         {
01007                 foreach(QString prop, getPropertyList()) {
01008                         foreach(QVPropertyContainer *container, getDestinySequentialContainers(prop)) {
01009                                 if (container->master != newMaster) {
01010                                         container->changeMaster(newMaster);
01011                                         container->propagateForwardMasterChange(newMaster);
01012                                         container->propagateBackwardMasterChange(newMaster);
01013                                 }
01014                         }
01015                 }
01016         }
01017 
01018 // the sequential subgraphs cannot have cicles
01019 void QVPropertyContainer::changeMaster(QVPropertyContainer *newMaster)
01020         {
01021                 master->slavesByLevel[deepLevel].removeAll(this);
01022                 master = newMaster;
01023 
01024                 while(master->slavesByLevel.size() <= deepLevel)
01025                         master->slavesByLevel.append(QList<QVPropertyContainer *>());
01026                 master->slavesByLevel[deepLevel].append(this);
01027         }
01028 
01029 // the sequential subgraphs cannot have cicles
01030 QList<QVPropertyContainer *> QVPropertyContainer::getDestinySequentialContainers(const QString name) const
01031         {
01032                 QList<QVPropertyContainer *> list;
01033 
01034                 if (outputLinks.contains(name))
01035                         foreach(QVPropertyContainerLink* link, outputLinks.value(name)) {
01036                                 if ( (link->qvp_dest != NULL) &&
01037                                          (link->markedForDeletion == FALSE) &&
01038                                          (!list.contains(link->qvp_dest)) &&
01039                                          (link->link_type == SequentialLink) ) list.append(link->qvp_dest);
01040                         }
01041 
01042                 return list;
01043         }



QVision framework. PARP research group, copyright 2007, 2008.