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(), 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
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(), 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) &&
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 bool isSequential = (link->link_type == SequentialLink);
00554 link->markedForDeletion = TRUE;
00555
00556
00557 link->SyncSemaphoreOut.release();
00558 destCont->treatUnlinkInputProperty(destName, this, origName);
00559
00560
00561
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
00586
00587 link->SyncSemaphoreIn.release();
00588
00589
00590
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
00600
00601 link->SyncSemaphoreOut.release();
00602 if (link->qvp_dest != NULL) link->qvp_dest->treatUnlinkInputProperty(link->prop_dest, this, link->prop_orig);
00603
00604
00605
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
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 QMutableMapIterator<QString, QVPropertyContainerLink*> i(inputLinks);
00625 while (i.hasNext()) {
00626 i.next();
00627 QVPropertyContainerLink *link = i.value();
00628
00629
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
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
00657
00658
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
00675
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
00688
00689
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
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++)
00780 {
00781 bool find = false;
00782
00783 if (conts.at(i)->getId() == conts.at(j)->getId())
00784 {
00785 dSet.unify(i, j);
00786 find = true;
00787 }
00788 if (!find)
00789 {
00790 const QMap<QString, QVPropertyContainerLink* > inLinksI = conts.at(i)->getInputLinks();
00791 foreach(QVPropertyContainerLink* proConLink, inLinksI.values())
00792 if ( (proConLink->qvp_orig->getId() == conts.at(j)->getId()) &&
00793 (proConLink->link_type != AsynchronousLink) )
00794 {
00795 dSet.unify(i, j);
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())
00804 if ( (proConLink->qvp_orig->getId() == conts.at(i)->getId()) &&
00805 (proConLink->link_type != AsynchronousLink) )
00806 {
00807 dSet.unify(i, j);
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
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
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
00863 setPropertyValue<double>(parameter,doubleValue);
00864 return TRUE;
00865 }
00866
00867 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value)
00868 {
00869
00870 setPropertyValue<QString>(parameter,value);
00871 return TRUE;
00872 }
00873
00874
00875 bool QVPropertyContainer::ProcessPosibleSequentialLink(QVPropertyContainer *destCont)
00876 {
00877
00878 if (haveSyncPrecursor(destCont))
00879 return false;
00880
00881
00882 if (destCont->haveSyncPrecursor(this))
00883 return true;
00884
00885
00886 destCont->updateDeep(deepLevel);
00887
00888
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
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
00912 foreach(QList<QVPropertyContainer *> level, loserMaster->slavesByLevel) {
00913 loserMaster->slavesByLevel.removeAll(level);
00914 }
00915 loserMaster->master = winnerMaster;
00916
00917 return true;
00918 }
00919
00920
00921 void QVPropertyContainer::updateDeep(int origDeep)
00922 {
00923 int newDeep = origDeep + 1;
00924 foreach(QVPropertyContainerLink* inLink, getInputLinks()) {
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) {
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
00946 void QVPropertyContainer::ProcessSequentialUnlink(QVPropertyContainer *destCont)
00947 {
00948
00949 if (destCont->haveSyncPrecursor(this)) return;
00950
00951
00952 if( (master != this) && !haveSyncPrecursor(master) && !master->haveSyncPrecursor(this) ) {
00953
00954 this->propagateBackwardMasterChange(this);
00955 this->propagateForwardMasterChange(this);
00956 this->changeMaster(this);
00957
00958
00959 this->updateDeep(-1);
00960
00961
00962 destCont->updateDeep(-1);
00963 }
00964
00965 else if( (master != destCont) && !destCont->haveSyncPrecursor(destCont->master) && !destCont->master->haveSyncPrecursor(destCont) ) {
00966
00967 destCont->propagateBackwardMasterChange(destCont);
00968 destCont->propagateForwardMasterChange(destCont);
00969 destCont->changeMaster(destCont);
00970
00971
00972 destCont->updateDeep(-1);
00973 }
00974 }
00975
00976
00977 bool QVPropertyContainer::haveSyncPrecursor(QVPropertyContainer *precursor)
00978 {
00979 foreach(QString prop, getPropertyList()) {
00980 if (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
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
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
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
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 }