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 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 }
00215 return variants[name];
00216 }
00217
00218 QString QVPropertyContainer::getPropertyInfo(const QString name, bool *ok) const
00219 {
00220 if(not checkExists(name,"QVPropertyContainer::getPropertyInfo()")) {
00221 if(ok != NULL) *ok = FALSE;
00222 } else {
00223 if(ok != NULL) *ok = TRUE;
00224 }
00225 return this->_info[name];
00226 }
00227
00228 QString QVPropertyContainer::getLastError() const
00229 {
00230 return errorString;
00231 }
00232
00233 const QString QVPropertyContainer::infoInputProperties() const
00234 {
00235 qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ")";
00236
00237 QString info = QString("Input parameters for ") + getName() + QString(":\n");
00238 bool emptyInfo=TRUE;
00239
00240 qDebug() << "QVPropertyContainer::infoInputProperties(): Properties " << insertion_order;
00241
00242 foreach (QString property, insertion_order)
00243
00244
00245 {
00246
00247
00248 if( not isInput(property) )
00249 continue;
00250
00251 bool printableProperty = TRUE;
00252 QString propertyInfo(" --" + property + "=");
00253
00254 switch(getPropertyType(property))
00255 {
00256 case QVariant::String:
00257 propertyInfo += QString() + "[text] " + "(def. '" + getPropertyValue<QString>(property) + "') ";
00258 break;
00259
00260 case QVariant::Double:
00261 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00262 "[" + QString().setNum(getPropertyMinimum<double>(property)) + "..."
00263 + QString().setNum(getPropertyMaximum<double>(property)) + "] ":
00264 "[double] " ) + "(def. "+ QString().setNum(getPropertyValue<double>(property)) + ") ";
00265 break;
00266
00267 case QVariant::Int:
00268 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00269 "[" + QString().setNum(getPropertyMinimum<int>(property)) + "..." +
00270 QString().setNum(getPropertyMaximum<int>(property)) + "] ":
00271 "[int] " ) + "(def. "+ QString().setNum(getPropertyValue<int>(property)) + ") ";
00272 break;
00273
00274 case QVariant::Bool:
00275 propertyInfo += "[true,false]" + (getPropertyValue<bool>(property) ?
00276 QString(" (def. true) "):QString("(def. false) "));
00277 break;
00278
00279 default:
00280 printableProperty = FALSE;
00281 break;
00282 }
00283
00284 if (printableProperty)
00285 {
00286 info += propertyInfo + getPropertyInfo(property).rightJustified(100-propertyInfo.split('\n').last().length(),'.') + ".\n";
00287 emptyInfo=FALSE;
00288 }
00289 }
00290
00291 qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ") <~ return";
00292
00293 if(emptyInfo)
00294 return QString("");
00295
00296 return info;
00297 }
00298
00299 bool QVPropertyContainer::correctRange(const QString name, const double & value) const
00300 {
00301 if(not maximum.contains(name) and not minimum.contains(name))
00302 return TRUE;
00303 double maximum = getPropertyMaximum<double>(name);
00304 double minimum = getPropertyMinimum<double>(name);
00305 if(minimum <= value and maximum >= value)
00306 return TRUE;
00307 else
00308 {
00309 QString str = "QVPropertyContainer::setPropertyValue(): value " +
00310 QString("%1").arg(value) + " for property " +
00311 name + " in holder " + getName() +
00312 "is not valid for the specified range [" +
00313 QString("%1,%2").arg(minimum).arg(maximum) +
00314 "]" ;
00315 setLastError(str);
00316 if(qvApp->isRunning())
00317 {
00318 std::cerr << qPrintable("Warning: " + str + "\n");
00319 }
00320 return FALSE;
00321 }
00322 }
00323
00324 bool QVPropertyContainer::correctRange(const char *name, const int & value) const
00325 { return correctRange(QString(name),static_cast<double>(value)); }
00326
00327 bool QVPropertyContainer::correctRange(QString name, const int & value) const
00328 { return correctRange(name,static_cast<double>(value)); }
00329
00330 bool QVPropertyContainer::checkExists(const QString name, const QString methodname) const
00331 {
00332 if(not variants.contains(name))
00333 {
00334 QString str = methodname + ": property " + name +
00335 " doesn't exists in holder " + getName() + ".";
00336 setLastError(str);
00337 if(qvApp->isRunning()) {
00338 std::cerr << qPrintable("Warning: " + str + "\n");
00339 }
00340 return FALSE;
00341 } else {
00342 return TRUE;
00343 }
00344 }
00345
00346 bool QVPropertyContainer::checkIsNewProperty(const QString name, const QString methodname) const
00347 {
00348 if(variants.contains(name))
00349 {
00350 QString str = methodname + "(): property " + name +
00351 " already exists in holder " + getName() + ".";
00352 setLastError(str);
00353 if(qvApp->isRunning()) {
00354 std::cerr << qPrintable("Warning: " + str + "\n");
00355 }
00356 return FALSE;
00357 } else {
00358 return TRUE;
00359 }
00360 }
00361
00363
00364 bool QVPropertyContainer::linkProperty(QString prop_orig, QVPropertyContainer *qvp_dest, QString prop_dest, LinkType link_type)
00365 {
00366 bool ok1,ok2;
00367 QString errMsg;
00368 int t1,t2;
00369 QVPropertyContainer *qvp_err=NULL;
00370
00371 t1 = this->getPropertyType(prop_orig,&ok1);
00372 t2 = qvp_dest->getPropertyType(prop_dest,&ok2);
00373 if(qvApp->isRunning())
00374 {
00375 qvp_err = this;
00376 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1:"
00377 "Cannot link properties after launching QVApplication.\n")
00378 .arg(prop_orig).arg(this->getName());
00379 }
00380 else if(this == qvp_dest)
00381 {
00382 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1: cannot link a QVPropertyContainer with itself.\n").arg(this->getName());
00383 qvp_err = this;
00384 }
00385 else if(not ok1)
00386 {
00387 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00388 .arg(prop_orig).arg(this->getName());
00389 qvp_err = this;
00390 }
00391 else if (not ok2)
00392 {
00393 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00394 .arg(prop_dest).arg(qvp_dest->getName());
00395 qvp_err = qvp_dest;
00396 }
00397 else if(t1 != t2)
00398 {
00399 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());
00400 qvp_err = this;
00401 }
00402 else if(not (this->io_flags[prop_orig] & outputFlag))
00403 {
00404 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());
00405 qvp_err = this;
00406 }
00407 else if(not (qvp_dest->io_flags[prop_dest] & inputFlag))
00408 {
00409 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());
00410 qvp_err = qvp_dest;
00411 }
00412 else if( (link_type == SequentialLink) && (!ProcessPosibleSequentialLink(qvp_dest)) )
00413 {
00414 errMsg = QString("QVPropertyContainer::linkProperty(): A new link cannot generate a cycle of SequentialLinks.\n");
00415 qvp_err = this;
00416 }
00417
00418 if(errMsg != QString())
00419 {
00420 qvp_err->setLastError(errMsg);
00421 if(qvApp->isRunning()) {
00422 std::cerr << qPrintable("Warning: " + errMsg + "\n");
00423 }
00424 return FALSE;
00425 }
00426 else
00427 {
00428 QVPropertyContainerLink *link = new QVPropertyContainerLink(this,prop_orig,qvp_dest,prop_dest,link_type);
00429 this->outputLinks[prop_orig].push_back(link);
00430 this->link_flags[prop_orig] |= linkedOutputFlag;
00431
00432
00433
00434 qvp_dest->addInputLink(prop_dest, link);
00435
00436
00437
00438 this->RWLock.lockForWrite();
00439 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00440 this->RWLock.unlock();
00441
00442 if (link_type == QVPropertyContainer::AsynchronousLink)
00443 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));
00444 else if (link_type == QVPropertyContainer::SynchronousLink)
00445 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));
00446 else
00447 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));
00448
00449 return TRUE;
00450 }
00451 }
00452
00453 bool QVPropertyContainer::linkProperty(QVPropertyContainer *destinyContainer, QString destinyPropertyName, LinkType linkType)
00454 {
00455 if (linkUnspecifiedOutputProperty(destinyContainer, destinyPropertyName, linkType))
00456 return true;
00457 else {
00458 std::cerr << "ERROR: QVPropertyContainer::linkProperty(): source container " << qPrintable(getName()) << " can't handle unspecified output properties linking" << std::endl;
00459 return false;
00460 }
00461 }
00462
00463 bool QVPropertyContainer::linkProperty(QString sourcePropertyName, QVPropertyContainer *destinyContainer, LinkType linkType)
00464 {
00465 if (destinyContainer->linkUnspecifiedInputProperty(this, sourcePropertyName, linkType))
00466 return true;
00467 else {
00468 std::cerr << "ERROR: QVPropertyContainer::linkProperty(): destination container " << qPrintable(destinyContainer->getName()) << " can't handle unspecified input properties linking" << std::endl;
00469 return false;
00470 }
00471 }
00472
00473 void QVPropertyContainer::linkProperty(QVPropertyContainer *container, LinkType linkType)
00474 {
00475 QList<QString> localProper = getPropertyList();
00476 QList<QString> inputProper = container->getPropertyList();
00477
00478 qSort(localProper.begin(), localProper.end());
00479 qSort(inputProper.begin(), inputProper.end());
00480
00481 int i=0, l=0;
00482 while ( (i < inputProper.size()) && (l < localProper.size()) )
00483 {
00484 QString localName = localProper[l];
00485 QString inputName = inputProper[i];
00486 if (
00487 (localName == inputName) &&
00488 (getPropertyType(localName) == container->getPropertyType(inputName)) &&
00489 (io_flags[localName] & outputFlag) &&
00490 (container->io_flags[inputName] & inputFlag) &&
00491 (!(io_flags[localName] & internalProp)) &&
00492 (!(container->io_flags[inputName] & internalProp))
00493 )
00494 linkProperty(localProper[l], container, inputProper[i], linkType);
00495
00496 if(localName <= inputName) l++;
00497 if(localName >= inputName) i++;
00498 }
00499 }
00500
00502
00503 bool QVPropertyContainer::linkProperty(QString prop_orig, QVPropertyContainer &qvp_dest, QString prop_dest, LinkType link_type)
00504 {
00505 return linkProperty(prop_orig, &qvp_dest, prop_dest, link_type);
00506 }
00507
00508 bool QVPropertyContainer::linkProperty(QVPropertyContainer &destinyContainer, QString destinyPropertyName, LinkType linkType)
00509 {
00510 return linkProperty(&destinyContainer, destinyPropertyName, linkType);
00511 }
00512
00513 bool QVPropertyContainer::linkProperty(QString sourcePropertyName, QVPropertyContainer &destinyContainer, LinkType linkType)
00514 {
00515 return linkProperty(sourcePropertyName, &destinyContainer, linkType);
00516 }
00517
00518 void QVPropertyContainer::linkProperty(QVPropertyContainer &container, LinkType linkType)
00519 {
00520 linkProperty(&container, linkType);
00521 }
00522
00524
00525 bool QVPropertyContainer::linkUnspecifiedInputProperty(QVPropertyContainer *srcCont, QString srcProp, LinkType linkType)
00526 {
00527 if (containsProperty(srcProp))
00528 return srcCont->linkProperty(srcProp, this, srcProp, linkType);
00529 else
00530 return false;
00531 }
00532
00533 bool QVPropertyContainer::linkUnspecifiedOutputProperty(QVPropertyContainer *dstCont, QString dstProp, LinkType linkType)
00534 {
00535 if (containsProperty(dstProp))
00536 return linkProperty(dstProp, dstCont, dstProp, linkType);
00537 else
00538 return false;
00539 }
00540
00542
00543 void QVPropertyContainer::addInputLink(QString prop_dest, QVPropertyContainerLink *link)
00544 {
00545 inputLinks[prop_dest] = link;
00546 link_flags[prop_dest] |= linkedInputFlag;
00547 }
00548
00549 bool QVPropertyContainer::unlinkProperty(QString origName, QVPropertyContainer *destCont, QString destName)
00550 {
00551 QList<QVPropertyContainerLink*> linkList = outputLinks[origName];
00552 foreach(QVPropertyContainerLink* link, linkList) {
00553 if ( (link->qvp_orig == this) && (link->prop_orig == origName) &&
00554 (link->qvp_dest == destCont) && (link->prop_dest == destName) ) {
00555 if (!link->markedForDeletion) {
00556 bool isSequential = (link->link_type == SequentialLink) ? true : false;
00557 link->markedForDeletion = TRUE;
00558
00559
00560 link->SyncSemaphoreOut.release();
00561 destCont->treatUnlinkInputProperty(destName, this, origName);
00562
00563
00564
00565 if (isSequential) ProcessSequentialUnlink(this, destCont);
00566 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::LinkDel, this->getName(), this->getId(), origName, destCont->getName(), destCont->getId(), destName));
00567 }
00568 return TRUE;
00569 }
00570 }
00571 return FALSE;
00572 }
00573
00574 bool QVPropertyContainer::unlinkProperty(QString origName, QVPropertyContainer &destCont, QString destName)
00575 {
00576 return unlinkProperty(origName, &destCont, destName);
00577 }
00578
00579 bool QVPropertyContainer::treatUnlinkInputProperty(QString, QVPropertyContainer *, QString)
00580 {
00581 return true;
00582 }
00583
00584 void QVPropertyContainer::unlink()
00585 {
00586 foreach(QVPropertyContainerLink* link, inputLinks.values()) {
00587 if (!link->markedForDeletion) {
00588 bool isSequential = (link->link_type == SequentialLink) ? true : false;
00589 link->markedForDeletion = TRUE;
00590
00591
00592 link->SyncSemaphoreIn.release();
00593
00594
00595
00596 if (isSequential) ProcessSequentialUnlink(link->qvp_orig, link->qvp_dest);
00597 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));
00598 }
00599 }
00600
00601 foreach(QList<QVPropertyContainerLink*> linkList, outputLinks.values()) {
00602 foreach(QVPropertyContainerLink* link, linkList) {
00603 if (!link->markedForDeletion) {
00604 bool isSequential = (link->link_type == SequentialLink) ? true : false;
00605 link->markedForDeletion = TRUE;
00606
00607
00608 link->SyncSemaphoreOut.release();
00609 if (link->qvp_dest != NULL) link->qvp_dest->treatUnlinkInputProperty(link->prop_dest, this, link->prop_orig);
00610
00611
00612
00613 if (isSequential) ProcessSequentialUnlink(link->qvp_orig, link->qvp_dest);
00614 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));
00615 }
00616 }
00617 }
00618 }
00619
00620 void QVPropertyContainer::readInputProperties()
00621 {
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632 QMutableMapIterator<QString, QVPropertyContainerLink*> i(inputLinks);
00633 while (i.hasNext()) {
00634 i.next();
00635 QVPropertyContainerLink *link = i.value();
00636
00637
00638 if(link->markedForDeletion) {
00639 i.remove();
00640 toDeleteLink(link);
00641 }
00642 else {
00643 if(link->link_type == SynchronousLink) {
00644 link->SyncSemaphoreOut.acquire();
00645 }
00646 if (link->link_type != SequentialLink)
00647 link->qvp_orig->RWLock.lockForRead();
00648
00649 this->variants[link->prop_dest] = link->qvp_orig->safelyCopiedVariants[link->prop_orig];
00650 if (link->link_type != SequentialLink)
00651 link->qvp_orig->RWLock.unlock();
00652 if(link->link_type == SynchronousLink) {
00653 link->SyncSemaphoreIn.release();
00654 }
00655 }
00656 }
00657 informer.emitChange(QVPropertyContainerChange(this->getName(), this->getId(), QVPropertyContainerChange::PropertiesValues));
00658 }
00659
00660 void QVPropertyContainer::writeOutputProperties()
00661 {
00662 QMutableMapIterator<QString, QList<QVPropertyContainerLink*> >i(outputLinks);
00663
00664
00665
00666
00667 bool someSequential = false;
00668 while (i.hasNext()) {
00669 i.next();
00670 QListIterator<QVPropertyContainerLink*> j(i.value());
00671 while(j.hasNext()) {
00672 QVPropertyContainerLink *link = j.next();
00673 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00674 link->SyncSemaphoreIn.acquire();
00675 }
00676 else if(link->link_type == SequentialLink and not link->markedForDeletion) {
00677 someSequential = true;
00678 }
00679 }
00680 }
00681
00682
00683
00684 i.toFront();
00685 if (!someSequential)
00686 this->RWLock.lockForWrite();
00687 while (i.hasNext()) {
00688 i.next();
00689 QString prop_orig = i.key();
00690 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00691 }
00692 if (!someSequential)
00693 this->RWLock.unlock();
00694
00695
00696
00697
00698 i.toFront();
00699 while (i.hasNext()) {
00700 i.next();
00701 QMutableListIterator<QVPropertyContainerLink*> j(i.value());
00702 while(j.hasNext()) {
00703 QVPropertyContainerLink *link = j.next();
00704 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00705 link->SyncSemaphoreOut.release();
00706 }
00707
00708 if(link->markedForDeletion) {
00709 j.remove();
00710 toDeleteLink(link);
00711 if(i.value().isEmpty()) {
00712 i.remove();
00713 break;
00714 }
00715 }
00716 }
00717 }
00718 }
00719
00720 void QVPropertyContainer::toDeleteLink(QVPropertyContainerLink* link)
00721 {
00722 if (link->qvp_orig == this) {
00723 link->qvp_orig = NULL;
00724 }
00725 else if (link->qvp_dest == this) {
00726 link->qvp_dest = NULL;
00727 }
00728
00729 if ((link->qvp_orig == NULL) && (link->qvp_dest == NULL)) delete link;
00730 }
00731
00732 void QVPropertyContainer::setLastError(QString str) const
00733 { errorString = str; }
00734
00735 QVPropertyContainer *QVPropertyContainer::getSourceContainer(const QString name) const
00736 {
00737 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00738 if (inLinks.contains(name))
00739 return inLinks.value(name)->qvp_orig;
00740
00741 return NULL;
00742 }
00743
00744 QList<QVPropertyContainer *> QVPropertyContainer::getDestinyContainers(const QString name) const
00745 {
00746 QList<QVPropertyContainer *> list;
00747
00748 if (outputLinks.contains(name))
00749 foreach(QVPropertyContainerLink* link, outputLinks.value(name))
00750 if ( (link->qvp_dest != NULL) && (!list.contains(link->qvp_dest)) ) list.append(link->qvp_dest);
00751
00752 return list;
00753 }
00754
00755 QString QVPropertyContainer::getSourceProperty(const QString name) const
00756 {
00757 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00758 if (inLinks.contains(name))
00759 return inLinks.value(name)->prop_orig;
00760
00761 return QString();
00762 }
00763
00764 bool QVPropertyContainer::isSynchronous(const QString name) const
00765 {
00766 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00767 if (inLinks.contains(name))
00768 return (inLinks.value(name)->link_type == SynchronousLink);
00769
00770 return FALSE;
00771 }
00772
00773 bool QVPropertyContainer::isSequential(const QString name) const
00774 {
00775 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
00776 if (inLinks.contains(name))
00777 return (inLinks.value(name)->link_type == SequentialLink);
00778
00779 return FALSE;
00780 }
00781
00782 bool QVPropertyContainer::areSynchronized(const QList<QVPropertyContainer *> conts)
00783 {
00784 QVDisjointSet dSet(conts.size());
00785
00786 for (int i = 0; i < conts.size(); i++)
00787 for (int j = i+1; j < conts.size(); j++)
00788 {
00789 bool find = false;
00790
00791 if (conts.at(i)->getId() == conts.at(j)->getId())
00792 {
00793 dSet.unify(i, j);
00794 find = true;
00795 }
00796 if (!find)
00797 {
00798 const QMap<QString, QVPropertyContainerLink* > inLinksI = conts.at(i)->getInputLinks();
00799 foreach(QVPropertyContainerLink* proConLink, inLinksI.values())
00800 if ( (proConLink->qvp_orig_id == conts.at(j)->getId()) &&
00801 (proConLink->link_type != AsynchronousLink) )
00802 {
00803 dSet.unify(i, j);
00804 find = true;
00805 break;
00806 }
00807 }
00808 if (!find)
00809 {
00810 const QMap<QString, QVPropertyContainerLink* > inLinksJ = conts.at(j)->getInputLinks();
00811 foreach(QVPropertyContainerLink* proConLink, inLinksJ.values())
00812 if ( (proConLink->qvp_orig_id == conts.at(i)->getId()) &&
00813 (proConLink->link_type != AsynchronousLink) )
00814 {
00815 dSet.unify(i, j);
00816 break;
00817 }
00818 }
00819 }
00820
00821 return (dSet.numberOfSets() == 1);
00822 }
00823
00824 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value)
00825 {
00826 if (value.toLower() == "true" || value.toLower() == "false")
00827 {
00828
00829 setPropertyValue<bool>(parameter,value.toLower() == "true");
00830 return TRUE;
00831 }
00832 else {
00833 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00834 ": value " + value +
00835 " is not a valid boolean value for parameter " +
00836 parameter + ".\n";
00837 return FALSE;
00838 }
00839 }
00840
00841 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value)
00842 {
00843 bool okInt;
00844 int intValue = value.toInt(&okInt);
00845 if(not okInt)
00846 {
00847 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00848 ": value " + value +
00849 " is not a valid integer value for parameter " +
00850 parameter + ".\n";
00851 return FALSE;
00852 }
00853
00854 setPropertyValue<int>(parameter,intValue);
00855 return TRUE;
00856 }
00857
00858 template <> bool QVPropertyContainer::parseArgument<float>(const QString parameter, const QString value)
00859 {
00860 bool okFloat;
00861 float floatValue = value.toFloat(&okFloat);
00862 if(not okFloat) {
00863 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00864 ": value " + value +
00865 " is not a valid float value for parameter " +
00866 parameter + ".\n";
00867 return FALSE;
00868 }
00869
00870 setPropertyValue<float>(parameter,floatValue);
00871
00872 return TRUE;
00873 }
00874
00875 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value)
00876 {
00877 bool okDouble;
00878 double doubleValue = value.toDouble(&okDouble);
00879 if(not okDouble)
00880 {
00881 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00882 ": value " + value +
00883 " is not a valid double value for parameter " +
00884 parameter + ".\n";
00885 return FALSE;
00886 }
00887
00888 setPropertyValue<double>(parameter,doubleValue);
00889
00890 return TRUE;
00891 }
00892
00893 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value)
00894 {
00895
00896 setPropertyValue<QString>(parameter,value);
00897 return TRUE;
00898 }
00899
00900
00901 bool QVPropertyContainer::ProcessPosibleSequentialLink(QVPropertyContainer *destCont)
00902 {
00903
00904 if (haveSyncPrecursor(destCont))
00905 return false;
00906
00907
00908 if (destCont->haveSyncPrecursor(this))
00909 return true;
00910
00911
00912 destCont->updateDeep(deepLevel);
00913
00914
00915 QVPropertyContainer *winnerMaster, *loserMaster;
00916 if (this->master->getId() < destCont->master->getId()) {
00917 winnerMaster = this->master;
00918 loserMaster = destCont->master;
00919 }
00920 else {
00921 winnerMaster = destCont->master;
00922 loserMaster = this->master;
00923 }
00924
00925
00926 for(int i = 0; i < loserMaster->slavesByLevel.size(); i++) {
00927 if(winnerMaster->slavesByLevel.size() <= i)
00928 winnerMaster->slavesByLevel.append(QList<QVPropertyContainer *>());
00929
00930 QList<QVPropertyContainer *> level = loserMaster->slavesByLevel[i];
00931 foreach(QVPropertyContainer *slave, level) {
00932 slave->master = winnerMaster;
00933 winnerMaster->slavesByLevel[i].append(slave);
00934 }
00935 }
00936
00937
00938 foreach(QList<QVPropertyContainer *> level, loserMaster->slavesByLevel) {
00939 loserMaster->slavesByLevel.removeAll(level);
00940 }
00941
00942 return true;
00943 }
00944
00945
00946 void QVPropertyContainer::updateDeep(int origDeep)
00947 {
00948 int newDeep = origDeep + 1;
00949 foreach(QVPropertyContainerLink* inLink, getInputLinks()) {
00950 QVPropertyContainer *cont = inLink->qvp_orig;
00951 if ( (cont != NULL) && (inLink->markedForDeletion == FALSE) && (inLink->link_type == SequentialLink) )
00952 if (cont->deepLevel >= newDeep)
00953 newDeep = cont->deepLevel + 1;
00954 }
00955
00956 if (newDeep != deepLevel) {
00957 master->slavesByLevel[deepLevel].removeAll(this);
00958 deepLevel = newDeep;
00959
00960 while(master->slavesByLevel.size() <= deepLevel)
00961 master->slavesByLevel.append(QList<QVPropertyContainer *>());
00962 master->slavesByLevel[deepLevel].append(this);
00963
00964 foreach(QString prop, getPropertyList())
00965 foreach(QVPropertyContainer *container, getDestinySequentialContainers(prop))
00966 container->updateDeep(deepLevel);
00967 }
00968 }
00969
00970
00971 void QVPropertyContainer::ProcessSequentialUnlink(QVPropertyContainer *origCont, QVPropertyContainer *destCont)
00972 {
00973
00974 if (destCont->haveSyncPrecursor(origCont)) return;
00975
00976
00977 if( (origCont->master != origCont) && !origCont->haveSyncPrecursor(origCont->master) && !origCont->master->haveSyncPrecursor(origCont) ) {
00978
00979 origCont->changeMaster(origCont);
00980 origCont->propagateBackwardMasterChange(origCont);
00981 origCont->propagateForwardMasterChange(origCont);
00982
00983
00984 origCont->updateDeep(-1);
00985
00986
00987 destCont->updateDeep(-1);
00988 }
00989
00990 else if( (destCont->master != destCont) && !destCont->haveSyncPrecursor(destCont->master) && !destCont->master->haveSyncPrecursor(destCont) ) {
00991
00992 destCont->propagateBackwardMasterChange(destCont);
00993 destCont->propagateForwardMasterChange(destCont);
00994 destCont->changeMaster(destCont);
00995
00996
00997 destCont->updateDeep(-1);
00998 }
00999 }
01000
01001
01002 bool QVPropertyContainer::haveSyncPrecursor(QVPropertyContainer *precursor)
01003 {
01004 foreach(QString prop, getPropertyList()) {
01005 if (isSequential(prop)) {
01006 const QMap<QString, QVPropertyContainerLink* > inLinks = getInputLinks();
01007 QVPropertyContainer *cont = inLinks.value(prop)->qvp_orig;
01008 if ( (cont != NULL) && (inLinks.value(prop)->markedForDeletion == FALSE) )
01009 if ( (precursor == cont) || (cont->haveSyncPrecursor(precursor)) ) return true;
01010 }
01011 }
01012 return false;
01013 }
01014
01015
01016 void QVPropertyContainer::propagateBackwardMasterChange(QVPropertyContainer *newMaster)
01017 {
01018 foreach(QVPropertyContainerLink *link, getInputLinks()) {
01019 QVPropertyContainer *cont = link->qvp_orig;
01020 if ( (cont != NULL) && (link->markedForDeletion == FALSE) && (link->link_type == SequentialLink) && (cont->master != newMaster) ) {
01021 cont->changeMaster(newMaster);
01022 cont->propagateBackwardMasterChange(newMaster);
01023 cont->propagateForwardMasterChange(newMaster);
01024 }
01025 }
01026
01027 }
01028
01029
01030 void QVPropertyContainer::propagateForwardMasterChange(QVPropertyContainer *newMaster)
01031 {
01032 foreach(QString prop, getPropertyList()) {
01033 foreach(QVPropertyContainer *container, getDestinySequentialContainers(prop)) {
01034 if (container->master != newMaster) {
01035 container->changeMaster(newMaster);
01036 container->propagateForwardMasterChange(newMaster);
01037 container->propagateBackwardMasterChange(newMaster);
01038 }
01039 }
01040 }
01041 }
01042
01043
01044 void QVPropertyContainer::changeMaster(QVPropertyContainer *newMaster)
01045 {
01046 master->slavesByLevel[deepLevel].removeAll(this);
01047 master = newMaster;
01048
01049 while(master->slavesByLevel.size() <= deepLevel)
01050 master->slavesByLevel.append(QList<QVPropertyContainer *>());
01051 master->slavesByLevel[deepLevel].append(this);
01052 }
01053
01054
01055 QList<QVPropertyContainer *> QVPropertyContainer::getDestinySequentialContainers(const QString name) const
01056 {
01057 QList<QVPropertyContainer *> list;
01058
01059 if (outputLinks.contains(name))
01060 foreach(QVPropertyContainerLink* link, outputLinks.value(name)) {
01061 if ( (link->qvp_dest != NULL) &&
01062 (link->markedForDeletion == FALSE) &&
01063 (!list.contains(link->qvp_dest)) &&
01064 (link->link_type == SequentialLink) ) list.append(link->qvp_dest);
01065 }
01066
01067 return list;
01068 }