00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <QVDisjointSet>
00026 #include <QVPropertyContainer>
00027
00028 uint QVPropertyContainer::maxIdent = 0;
00029
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
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
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(), this->getId(), 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(), this->getId(), QVPropertyContainerChange::ContainerDel));
00114 }
00115
00116 void QVPropertyContainer::setName(const QString name)
00117 { this->name = name; informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), 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(), this->getId(), QVPropertyContainerChange::PropertyDel, name));
00159 return TRUE;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
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
00242
00243 {
00244
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 }
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 }
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 }
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 }
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
00430
00431
00432 qvp_dest->addInputLink(prop_dest, link);
00433
00434
00435
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(), this->getId(), QVPropertyContainerChange::LinkAdd, this->getName(), this->getId(), prop_orig, qvp_dest->getName(), qvp_dest->getId(), prop_dest,FALSE,FALSE));
00442 else if (link_type == QVPropertyContainer::SynchronousLink)
00443 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::LinkAdd, this->getName(), this->getId(), prop_orig, qvp_dest->getName(), qvp_dest->getId(), prop_dest,TRUE, FALSE));
00444 else
00445 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::LinkAdd, this->getName(), this->getId(), prop_orig, qvp_dest->getName(), qvp_dest->getId(), 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) &&
00486 (getPropertyType(localName) == container->getPropertyType(inputName)) &&
00487 (io_flags[localName] & outputFlag) &&
00488 (container->io_flags[inputName] & inputFlag) &&
00489 (!(io_flags[localName] & internalProp)) &&
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 if (!link->markedForDeletion) {
00554 bool isSequential = (link->link_type == SequentialLink) ? true : false;
00555 link->markedForDeletion = TRUE;
00556
00557
00558 link->SyncSemaphoreOut.release();
00559 destCont->treatUnlinkInputProperty(destName, this, origName);
00560
00561
00562
00563 if (isSequential) ProcessSequentialUnlink(this, destCont);
00564 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::LinkDel, this->getName(), this->getId(), origName, destCont->getName(), destCont->getId(), destName));
00565 }
00566 return TRUE;
00567 }
00568 }
00569 return FALSE;
00570 }
00571
00572 bool QVPropertyContainer::unlinkProperty(QString origName, QVPropertyContainer &destCont, QString destName)
00573 {
00574 return unlinkProperty(origName, &destCont, destName);
00575 }
00576
00577 bool QVPropertyContainer::treatUnlinkInputProperty(QString, QVPropertyContainer *, QString)
00578 {
00579 return true;
00580 }
00581
00582 void QVPropertyContainer::unlink()
00583 {
00584 foreach(QVPropertyContainerLink* link, inputLinks.values()) {
00585 if (!link->markedForDeletion) {
00586 bool isSequential = (link->link_type == SequentialLink) ? true : false;
00587 link->markedForDeletion = TRUE;
00588
00589
00590 link->SyncSemaphoreIn.release();
00591
00592
00593
00594 if (isSequential) ProcessSequentialUnlink(link->qvp_orig, link->qvp_dest);
00595 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::LinkDel, link->qvp_orig_name, link->qvp_orig_id, link->prop_orig, link->qvp_dest_name, link->qvp_dest_id, link->prop_dest));
00596 }
00597 }
00598
00599 foreach(QList<QVPropertyContainerLink*> linkList, outputLinks.values()) {
00600 foreach(QVPropertyContainerLink* link, linkList) {
00601 if (!link->markedForDeletion) {
00602 bool isSequential = (link->link_type == SequentialLink) ? true : false;
00603 link->markedForDeletion = TRUE;
00604
00605
00606 link->SyncSemaphoreOut.release();
00607 if (link->qvp_dest != NULL) link->qvp_dest->treatUnlinkInputProperty(link->prop_dest, this, link->prop_orig);
00608
00609
00610
00611 if (isSequential) ProcessSequentialUnlink(link->qvp_orig, link->qvp_dest);
00612 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::LinkDel, link->qvp_orig_name, link->qvp_orig_id, link->prop_orig, link->qvp_dest_name, link->qvp_dest_id, link->prop_dest));
00613 }
00614 }
00615 }
00616 }
00617
00618 void QVPropertyContainer::readInputProperties()
00619 {
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 QMutableMapIterator<QString, QVPropertyContainerLink*> i(inputLinks);
00631 while (i.hasNext()) {
00632 i.next();
00633 QVPropertyContainerLink *link = i.value();
00634
00635
00636 if(link->markedForDeletion) {
00637 i.remove();
00638 toDeleteLink(link);
00639 }
00640 else {
00641 if(link->link_type == SynchronousLink) {
00642 link->SyncSemaphoreOut.acquire();
00643 }
00644 if (link->link_type != SequentialLink)
00645 link->qvp_orig->RWLock.lockForRead();
00646
00647 this->variants[link->prop_dest] = link->qvp_orig->safelyCopiedVariants[link->prop_orig];
00648 if (link->link_type != SequentialLink)
00649 link->qvp_orig->RWLock.unlock();
00650 if(link->link_type == SynchronousLink) {
00651 link->SyncSemaphoreIn.release();
00652 }
00653 }
00654 }
00655 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::PropertiesValues));
00656 }
00657
00658 void QVPropertyContainer::writeOutputProperties()
00659 {
00660 QMutableMapIterator<QString, QList<QVPropertyContainerLink*> >i(outputLinks);
00661
00662
00663
00664
00665 bool someSequential = false;
00666 while (i.hasNext()) {
00667 i.next();
00668 QListIterator<QVPropertyContainerLink*> j(i.value());
00669 while(j.hasNext()) {
00670 QVPropertyContainerLink *link = j.next();
00671 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00672 link->SyncSemaphoreIn.acquire();
00673 }
00674 else if(link->link_type == SequentialLink and not link->markedForDeletion) {
00675 someSequential = true;
00676 }
00677 }
00678 }
00679
00680
00681
00682 i.toFront();
00683 if (!someSequential)
00684 this->RWLock.lockForWrite();
00685 while (i.hasNext()) {
00686 i.next();
00687 QString prop_orig = i.key();
00688 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00689 }
00690 if (!someSequential)
00691 this->RWLock.unlock();
00692
00693
00694
00695
00696 i.toFront();
00697 while (i.hasNext()) {
00698 i.next();
00699 QMutableListIterator<QVPropertyContainerLink*> j(i.value());
00700 while(j.hasNext()) {
00701 QVPropertyContainerLink *link = j.next();
00702 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00703 link->SyncSemaphoreOut.release();
00704 }
00705
00706 if(link->markedForDeletion) {
00707 j.remove();
00708 toDeleteLink(link);
00709 if(i.value().isEmpty()) {
00710 i.remove();
00711 break;
00712 }
00713 }
00714 }
00715 }
00716 }
00717
00718 void QVPropertyContainer::toDeleteLink(QVPropertyContainerLink* link)
00719 {
00720 if (link->qvp_orig == this) {
00721 link->qvp_orig = NULL;
00722 }
00723 else if (link->qvp_dest == this) {
00724 link->qvp_dest = NULL;
00725 }
00726
00727 if ((link->qvp_orig == NULL) && (link->qvp_dest == NULL)) delete link;
00728 }
00729
00730 void QVPropertyContainer::setLastError(QString str) const
00731 { errorString = str; }
00732
00733 QVPropertyContainer *QVPropertyContainer::getSourceContainer(const QString name) const
00734 {
00735 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00736 if (inLinks.contains(name))
00737 return inLinks.value(name)->qvp_orig;
00738
00739 return NULL;
00740 }
00741
00742 QList<QVPropertyContainer *> QVPropertyContainer::getDestinyContainers(const QString name) const
00743 {
00744 QList<QVPropertyContainer *> list;
00745
00746 if (outputLinks.contains(name))
00747 foreach(QVPropertyContainerLink* link, outputLinks.value(name))
00748 if ( (link->qvp_dest != NULL) && (!list.contains(link->qvp_dest)) ) list.append(link->qvp_dest);
00749
00750 return list;
00751 }
00752
00753 QString QVPropertyContainer::getSourceProperty(const QString name) const
00754 {
00755 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00756 if (inLinks.contains(name))
00757 return inLinks.value(name)->prop_orig;
00758
00759 return QString();
00760 }
00761
00762 bool QVPropertyContainer::isSynchronous(const QString name) const
00763 {
00764 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00765 if (inLinks.contains(name))
00766 return (inLinks.value(name)->link_type == SynchronousLink);
00767
00768 return FALSE;
00769 }
00770
00771 bool QVPropertyContainer::isSequential(const QString name) const
00772 {
00773 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00774 if (inLinks.contains(name))
00775 return (inLinks.value(name)->link_type == SequentialLink);
00776
00777 return FALSE;
00778 }
00779
00780 bool QVPropertyContainer::areSynchronized(const QList<QVPropertyContainer *> conts)
00781 {
00782 QVDisjointSet dSet(conts.size());
00783
00784 for (int i = 0; i < conts.size(); i++)
00785 for (int j = i+1; j < conts.size(); j++)
00786 {
00787 bool find = false;
00788
00789 if (conts.at(i)->getId() == conts.at(j)->getId())
00790 {
00791 dSet.unify(i, j);
00792 find = true;
00793 }
00794 if (!find)
00795 {
00796 const QMap<QString, QVPropertyContainerLink* > inLinksI = conts.at(i)->getInputLinks();
00797 foreach(QVPropertyContainerLink* proConLink, inLinksI.values())
00798 if ( (proConLink->qvp_orig_id == conts.at(j)->getId()) &&
00799 (proConLink->link_type != AsynchronousLink) )
00800 {
00801 dSet.unify(i, j);
00802 find = true;
00803 break;
00804 }
00805 }
00806 if (!find)
00807 {
00808 const QMap<QString, QVPropertyContainerLink* > inLinksJ = conts.at(j)->getInputLinks();
00809 foreach(QVPropertyContainerLink* proConLink, inLinksJ.values())
00810 if ( (proConLink->qvp_orig_id == conts.at(i)->getId()) &&
00811 (proConLink->link_type != AsynchronousLink) )
00812 {
00813 dSet.unify(i, j);
00814 break;
00815 }
00816 }
00817 }
00818
00819 return (dSet.numberOfSets() == 1);
00820 }
00821
00822 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value)
00823 {
00824 if (value.toLower() == "true" || value.toLower() == "false")
00825 {
00826
00827 setPropertyValue<bool>(parameter,value.toLower() == "true");
00828 return TRUE;
00829 }
00830 else {
00831 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00832 ": value " + value +
00833 " is not a valid boolean value for parameter " +
00834 parameter + ".\n";
00835 return FALSE;
00836 }
00837 }
00838
00839 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value)
00840 {
00841 bool okInt;
00842 int intValue = value.toInt(&okInt);
00843 if(not okInt)
00844 {
00845 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00846 ": value " + value +
00847 " is not a valid integer value for parameter " +
00848 parameter + ".\n";
00849 return FALSE;
00850 }
00851
00852 setPropertyValue<int>(parameter,intValue);
00853 return TRUE;
00854 }
00855
00856 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value)
00857 {
00858 bool okDouble;
00859 double doubleValue = value.toDouble(&okDouble);
00860 if(not okDouble)
00861 {
00862 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00863 ": value " + value +
00864 " is not a valid double value for parameter " +
00865 parameter + ".\n";
00866 return FALSE;
00867 }
00868
00869 setPropertyValue<double>(parameter,doubleValue);
00870 return TRUE;
00871 }
00872
00873 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value)
00874 {
00875
00876 setPropertyValue<QString>(parameter,value);
00877 return TRUE;
00878 }
00879
00880
00881 bool QVPropertyContainer::ProcessPosibleSequentialLink(QVPropertyContainer *destCont)
00882 {
00883
00884 if (haveSyncPrecursor(destCont))
00885 return false;
00886
00887
00888 if (destCont->haveSyncPrecursor(this))
00889 return true;
00890
00891
00892 destCont->updateDeep(deepLevel);
00893
00894
00895 QVPropertyContainer *winnerMaster, *loserMaster;
00896 if (this->master->getId() < destCont->master->getId()) {
00897 winnerMaster = this->master;
00898 loserMaster = destCont->master;
00899 }
00900 else {
00901 winnerMaster = destCont->master;
00902 loserMaster = this->master;
00903 }
00904
00905
00906 for(int i = 0; i < loserMaster->slavesByLevel.size(); i++) {
00907 if(winnerMaster->slavesByLevel.size() <= i)
00908 winnerMaster->slavesByLevel.append(QList<QVPropertyContainer *>());
00909
00910 QList<QVPropertyContainer *> level = loserMaster->slavesByLevel[i];
00911 foreach(QVPropertyContainer *slave, level) {
00912 slave->master = winnerMaster;
00913 winnerMaster->slavesByLevel[i].append(slave);
00914 }
00915 }
00916
00917
00918 foreach(QList<QVPropertyContainer *> level, loserMaster->slavesByLevel) {
00919 loserMaster->slavesByLevel.removeAll(level);
00920 }
00921
00922 return true;
00923 }
00924
00925
00926 void QVPropertyContainer::updateDeep(int origDeep)
00927 {
00928 int newDeep = origDeep + 1;
00929 foreach(QVPropertyContainerLink* inLink, getInputLinks()) {
00930 QVPropertyContainer *cont = inLink->qvp_orig;
00931 if ( (cont != NULL) && (inLink->markedForDeletion == FALSE) && (inLink->link_type == SequentialLink) )
00932 if (cont->deepLevel >= newDeep)
00933 newDeep = cont->deepLevel + 1;
00934 }
00935
00936 if (newDeep != deepLevel) {
00937 master->slavesByLevel[deepLevel].removeAll(this);
00938 deepLevel = newDeep;
00939
00940 while(master->slavesByLevel.size() <= deepLevel)
00941 master->slavesByLevel.append(QList<QVPropertyContainer *>());
00942 master->slavesByLevel[deepLevel].append(this);
00943
00944 foreach(QString prop, getPropertyList())
00945 foreach(QVPropertyContainer *container, getDestinySequentialContainers(prop))
00946 container->updateDeep(deepLevel);
00947 }
00948 }
00949
00950
00951 void QVPropertyContainer::ProcessSequentialUnlink(QVPropertyContainer *origCont, QVPropertyContainer *destCont)
00952 {
00953
00954 if (destCont->haveSyncPrecursor(origCont)) return;
00955
00956
00957 if( (origCont->master != origCont) && !origCont->haveSyncPrecursor(origCont->master) && !origCont->master->haveSyncPrecursor(origCont) ) {
00958
00959 origCont->changeMaster(origCont);
00960 origCont->propagateBackwardMasterChange(origCont);
00961 origCont->propagateForwardMasterChange(origCont);
00962
00963
00964 origCont->updateDeep(-1);
00965
00966
00967 destCont->updateDeep(-1);
00968 }
00969
00970 else if( (destCont->master != destCont) && !destCont->haveSyncPrecursor(destCont->master) && !destCont->master->haveSyncPrecursor(destCont) ) {
00971
00972 destCont->propagateBackwardMasterChange(destCont);
00973 destCont->propagateForwardMasterChange(destCont);
00974 destCont->changeMaster(destCont);
00975
00976
00977 destCont->updateDeep(-1);
00978 }
00979 }
00980
00981
00982 bool QVPropertyContainer::haveSyncPrecursor(QVPropertyContainer *precursor)
00983 {
00984 foreach(QString prop, getPropertyList()) {
00985 if (isSequential(prop)) {
00986 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00987 QVPropertyContainer *cont = inLinks.value(prop)->qvp_orig;
00988 if ( (cont != NULL) && (inLinks.value(prop)->markedForDeletion == FALSE) )
00989 if ( (precursor == cont) || (cont->haveSyncPrecursor(precursor)) ) return true;
00990 }
00991 }
00992 return false;
00993 }
00994
00995
00996 void QVPropertyContainer::propagateBackwardMasterChange(QVPropertyContainer *newMaster)
00997 {
00998 foreach(QVPropertyContainerLink *link, getInputLinks()) {
00999 QVPropertyContainer *cont = link->qvp_orig;
01000 if ( (cont != NULL) && (link->markedForDeletion == FALSE) && (link->link_type == SequentialLink) && (cont->master != newMaster) ) {
01001 cont->changeMaster(newMaster);
01002 cont->propagateBackwardMasterChange(newMaster);
01003 cont->propagateForwardMasterChange(newMaster);
01004 }
01005 }
01006
01007 }
01008
01009
01010 void QVPropertyContainer::propagateForwardMasterChange(QVPropertyContainer *newMaster)
01011 {
01012 foreach(QString prop, getPropertyList()) {
01013 foreach(QVPropertyContainer *container, getDestinySequentialContainers(prop)) {
01014 if (container->master != newMaster) {
01015 container->changeMaster(newMaster);
01016 container->propagateForwardMasterChange(newMaster);
01017 container->propagateBackwardMasterChange(newMaster);
01018 }
01019 }
01020 }
01021 }
01022
01023
01024 void QVPropertyContainer::changeMaster(QVPropertyContainer *newMaster)
01025 {
01026 master->slavesByLevel[deepLevel].removeAll(this);
01027 master = newMaster;
01028
01029 while(master->slavesByLevel.size() <= deepLevel)
01030 master->slavesByLevel.append(QList<QVPropertyContainer *>());
01031 master->slavesByLevel[deepLevel].append(this);
01032 }
01033
01034
01035 QList<QVPropertyContainer *> QVPropertyContainer::getDestinySequentialContainers(const QString name) const
01036 {
01037 QList<QVPropertyContainer *> list;
01038
01039 if (outputLinks.contains(name))
01040 foreach(QVPropertyContainerLink* link, outputLinks.value(name)) {
01041 if ( (link->qvp_dest != NULL) &&
01042 (link->markedForDeletion == FALSE) &&
01043 (!list.contains(link->qvp_dest)) &&
01044 (link->link_type == SequentialLink) ) list.append(link->qvp_dest);
01045 }
01046
01047 return list;
01048 }