00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvmath/qvdisjointset.h>
00026
00027 #include "qvpropertycontainer.h"
00028
00029 uint QVPropertyContainer::maxIdent = 0;
00030
00031 QVPropertyContainer::QVPropertyContainer(const QString name):
00032 name(name), errorString(), variants(), safelyCopiedVariants(), minimum(),
00033 maximum(), _info(), io_flags(), link_flags(), insertion_order(),
00034 inputLinks(), outputLinks()
00035 {
00036 ident = getNewIdent();
00037 qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ")";
00038 if(qvApp == NULL)
00039 {
00040 QString str = "QVPropertyContainer::QVPropertyContainer(): holder " + name +
00041 ": property holders cannot be created before the " +
00042 "QVApplication instance. Aborting now.";
00043 std::cerr << qPrintable(str) << std::endl;
00044 exit(1);
00045 }
00046 else
00047 qvApp->registerQVPropertyContainer(this);
00048 qDebug() << "QVPropertyContainer::QVPropertyContainer(" << name << ") <- return";
00049 }
00050
00051 QVPropertyContainer & QVPropertyContainer::operator=(const QVPropertyContainer &cont)
00052 {
00053 name = cont.name;
00054 ident = cont.ident;
00055 errorString = cont.errorString;
00056 variants = cont.variants;
00057 safelyCopiedVariants = cont.safelyCopiedVariants;
00058 minimum = cont.minimum;
00059 maximum = cont.maximum;
00060 _info = cont._info;
00061 io_flags = cont.io_flags;
00062 link_flags = cont.link_flags;
00063 insertion_order = cont.insertion_order;
00064 inputLinks = cont.inputLinks;
00065 outputLinks = cont.outputLinks;
00066
00067 return *this;
00068 }
00069
00070 QVPropertyContainer::~QVPropertyContainer()
00071 {
00072 if(qvApp != NULL)
00073 qvApp->deregisterQVPropertyContainer(this);
00074
00075 }
00076
00077 void QVPropertyContainer::setName(const QString name)
00078 { this->name = name; }
00079
00080 const QString QVPropertyContainer::getName() const
00081 { return this->name; }
00082
00083 const uint QVPropertyContainer::getId() const
00084 { return this->ident; }
00085
00086 bool QVPropertyContainer::operator==(const QVPropertyContainer &cont) const
00087 { return (ident == cont.ident); }
00088
00089 QList<QString> QVPropertyContainer::getPropertyList() const
00090 { return variants.keys(); }
00091
00092 bool QVPropertyContainer::containsProperty(const QString name) const
00093 { return variants.contains(name); }
00094
00095 int QVPropertyContainer::getPropertyType(const QString name, bool *ok) const
00096 {
00097 if(not checkExists(name,"QVPropertyContainer::getPropertyType()"))
00098 {
00099 if(ok != NULL) *ok = FALSE;
00100 return QVariant::Invalid;
00101 }
00102 if(ok != NULL) *ok = TRUE;
00103 QVariant variant = variants.value(name);
00104 return variant.userType();
00105 }
00106
00107 bool QVPropertyContainer::removeProperty(const QString name)
00108 {
00109 if(not checkExists(name,"QVPropertyContainer::removeProperty()"))
00110 return FALSE;
00111 this->variants.remove(name);
00112 this->safelyCopiedVariants.remove(name);
00113 this->minimum.remove(name);
00114 this->maximum.remove(name);
00115 this->_info.remove(name);
00116 this->io_flags.remove(name);
00117 int i = this->insertion_order.indexOf(name);
00118 this->insertion_order.removeAt(i);
00119 return TRUE;
00120 }
00121
00122 bool QVPropertyContainer::setPropertyRange(const QString name, const double & minimum, const double & maximum)
00123 {
00124 std::cerr << "WARNING: setPropertyRange() is deprecated. Specify range in the function addProperty instead." << std::endl;
00125 if(not checkExists(name,"QVPropertyContainer::setPropertyRange()"))
00126 return FALSE;
00127 if(minimum <= getPropertyValue<double>(name) and
00128 maximum >= getPropertyValue<double>(name))
00129 {
00130 this->minimum[name] = QVariant::fromValue(minimum);
00131 this->maximum[name] = QVariant::fromValue(maximum);
00132 return TRUE;
00133 } else {
00134 QString str = "QVPropertyContainer::setPropertyRange(): property " +
00135 name + " in holder " + getName() + " has value " +
00136 QString("%1").arg(getPropertyValue<double>(name)) +
00137 ", which is not valid for the range [" +
00138 QString("%1,%2").arg(minimum).arg(maximum) + "]." ;
00139 setLastError(str);
00140 if(qvApp->isRunning()) {
00141 std::cerr << qPrintable("Warning: " + str + "\n");
00142 }
00143 return FALSE;
00144 }
00145 }
00146
00147 bool QVPropertyContainer::setPropertyRange(QString name, int & minimum, int & maximum)
00148 { return setPropertyRange(name, static_cast<double>(minimum), static_cast<double>(maximum)); }
00149
00150 bool QVPropertyContainer::hasRange(const QString name) const
00151 { return maximum.contains(name) and minimum.contains(name); }
00152
00153 bool QVPropertyContainer::isInput(const QString name) const
00154 { return (io_flags[name] & inputFlag);};
00155
00156 bool QVPropertyContainer::isOutput(const QString name) const
00157 { return (io_flags[name] & outputFlag);};
00158
00159 bool QVPropertyContainer::isGUIInvisible(const QString name) const
00160 { return (io_flags[name] & guiInvisible);};
00161
00162 bool QVPropertyContainer::isLinkedInput(const QString name) const
00163 { return (link_flags[name] & linkedInputFlag);};
00164
00165 bool QVPropertyContainer::isLinkedOutput(const QString name) const
00166 { return (link_flags[name] & linkedOutputFlag);};
00167
00168 QVariant QVPropertyContainer::getPropertyQVariantValue(const QString name, bool *ok) const
00169 {
00170 if (not checkExists(name,"QVPropertyContainer::getPropertyQVariantValue()"))
00171 if(ok != NULL) *ok = FALSE;
00172 else
00173 if(ok != NULL) *ok = TRUE;
00174 return variants[name];
00175 }
00176
00177 QString QVPropertyContainer::getPropertyInfo(const QString name, bool *ok) const
00178 {
00179 if(not checkExists(name,"QVPropertyContainer::getPropertyInfo()"))
00180 if(ok != NULL) *ok = FALSE;
00181 else
00182 if(ok != NULL) *ok = TRUE;
00183 return this->_info[name];
00184 }
00185
00186 QString QVPropertyContainer::getLastError() const
00187 {
00188 return errorString;
00189 }
00190
00191 const QString QVPropertyContainer::infoInputProperties() const
00192 {
00193 qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ")";
00194
00195 QString info = QString("Input parameters for ") + getName() + QString(":\n");
00196 bool emptyInfo=TRUE;
00197
00198 qDebug() << "QVPropertyContainer::infoInputProperties(): Properties " << insertion_order;
00199
00200 foreach (QString property, insertion_order)
00201
00202
00203 {
00204
00205
00206 if( not isInput(property) )
00207 continue;
00208
00209 bool printableProperty = TRUE;
00210 QString propertyInfo(" --" + property + "=");
00211
00212 switch(getPropertyType(property))
00213 {
00214 case QVariant::String:
00215 propertyInfo += QString() + "[text] " + "(def. '" + getPropertyValue<QString>(property) + "') ";
00216 break;
00217
00218 case QVariant::Double:
00219 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00220 "[" + QString().setNum(getPropertyMinimum<double>(property)) + "..."
00221 + QString().setNum(getPropertyMaximum<double>(property)) + "] ":
00222 "[double] " ) + "(def. "+ QString().setNum(getPropertyValue<double>(property)) + ") ";
00223 break;
00224
00225 case QVariant::Int:
00226 propertyInfo += ( (maximum.contains(property) and minimum.contains(property))?
00227 "[" + QString().setNum(getPropertyMinimum<int>(property)) + "..." +
00228 QString().setNum(getPropertyMaximum<int>(property)) + "] ":
00229 "[int] " ) + "(def. "+ QString().setNum(getPropertyValue<int>(property)) + ") ";
00230 break;
00231
00232 case QVariant::Bool:
00233 propertyInfo += "[true,false]" + (getPropertyValue<bool>(property) ?
00234 QString(" (def. true) "):QString("(def. false) "));
00235 break;
00236
00237 default:
00238 printableProperty = FALSE;
00239 break;
00240 }
00241
00242 if (printableProperty)
00243 {
00244 info += propertyInfo + getPropertyInfo(property).rightJustified(100-propertyInfo.split('\n').last().length(),' ') + ".\n";
00245 emptyInfo=FALSE;
00246 }
00247 }
00248
00249 qDebug() << "QVPropertyContainer::infoInputProperties(" << getName() << ") <~ return";
00250
00251 if(emptyInfo)
00252 return QString("");
00253
00254 return info;
00255 }
00256
00257 bool QVPropertyContainer::correctRange(const QString name, const double & value) const
00258 {
00259 if(not maximum.contains(name) and not minimum.contains(name))
00260 return TRUE;
00261 double maximum = getPropertyMaximum<double>(name);
00262 double minimum = getPropertyMinimum<double>(name);
00263 if(minimum <= value and maximum >= value)
00264 return TRUE;
00265 else
00266 {
00267 QString str = "QVPropertyContainer::setPropertyValue(): value " +
00268 QString("%1").arg(value) + " for property " +
00269 name + " in holder " + getName() +
00270 "is not valid for the range [" +
00271 QString("%1,%2").arg(minimum).arg(maximum) +
00272 "] stablished for it." ;
00273 setLastError(str);
00274 if(qvApp->isRunning())
00275 {
00276 std::cerr << qPrintable("Warning: " + str + "\n");
00277 }
00278 return FALSE;
00279 }
00280 }
00281
00282 bool QVPropertyContainer::correctRange(const char *name, const int & value) const
00283 { return correctRange(QString(name),static_cast<double>(value)); }
00284
00285 bool QVPropertyContainer::correctRange(QString name, const int & value) const
00286 { return correctRange(name,static_cast<double>(value)); }
00287
00288 bool QVPropertyContainer::checkExists(const QString name, const QString methodname) const
00289 {
00290 if(not variants.contains(name))
00291 {
00292 QString str = methodname + ": property " + name +
00293 " doesn't exists in holder " + getName() + ".";
00294 setLastError(str);
00295 if(qvApp->isRunning()) {
00296 std::cerr << qPrintable("Warning: " + str + "\n");
00297 }
00298 return FALSE;
00299 } else {
00300 return TRUE;
00301 }
00302 }
00303
00304 bool QVPropertyContainer::checkIsNewProperty(const QString name, const QString methodname) const
00305 {
00306 if(variants.contains(name))
00307 {
00308 QString str = methodname + "(): property " + name +
00309 " already exists in holder " + getName() + ".";
00310 setLastError(str);
00311 if(qvApp->isRunning()) {
00312 std::cerr << qPrintable("Warning: " + str + "\n");
00313 }
00314 return FALSE;
00315 } else {
00316 return TRUE;
00317 }
00318 }
00319
00320 bool QVPropertyContainer::linkProperty(QString prop_orig, QVPropertyContainer *qvp_dest, QString prop_dest, LinkType link_type)
00321 {
00322 bool ok1,ok2;
00323 QString errMsg;
00324 int t1,t2;
00325 QVPropertyContainer *qvp_orig=this, *qvp_err=NULL;
00326
00327 t1 = qvp_orig->getPropertyType(prop_orig,&ok1);
00328 t2 = qvp_dest->getPropertyType(prop_dest,&ok2);
00329 if(qvApp->isRunning())
00330 {
00331 qvp_err = qvp_orig;
00332 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1:"
00333 "Cannot link properties after launching QVApplication.\n")
00334 .arg(prop_orig).arg(qvp_orig->getName());
00335 }
00336 else if(qvp_orig == qvp_dest)
00337 {
00338 errMsg = QString("QVPropertyContainer::linkProperty(): Property holder %1: cannot link a QVPropertyContainer with itself.\n").arg(qvp_orig->getName());
00339 qvp_err = qvp_orig;
00340 }
00341 else if(not ok1)
00342 {
00343 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00344 .arg(prop_orig).arg(qvp_orig->getName());
00345 qvp_err = qvp_orig;
00346 }
00347 else if (not ok2)
00348 {
00349 errMsg = QString("QVPropertyContainer::linkProperty(): Property %1 does not exist in property holder %2.\n")
00350 .arg(prop_dest).arg(qvp_dest->getName());
00351 qvp_err = qvp_dest;
00352 }
00353 else if(t1 != t2)
00354 {
00355 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(qvp_orig->getName()).arg(qvp_dest->getName());
00356 qvp_err = qvp_orig;
00357 }
00358 else if(not (qvp_orig->io_flags[prop_orig] & outputFlag))
00359 {
00360 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(qvp_orig->getName());
00361 qvp_err = qvp_orig;
00362 }
00363 else if(not (qvp_dest->io_flags[prop_dest] & inputFlag))
00364 {
00365 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());
00366 qvp_err = qvp_dest;
00367 }
00368
00369 if(errMsg != QString())
00370 {
00371 qvp_err->setLastError(errMsg);
00372 if(qvApp->isRunning()) {
00373 std::cerr << qPrintable("Warning: " + errMsg + "\n");
00374 }
00375 return FALSE;
00376 }
00377 else
00378 {
00379 QVPropertyContainerLink *link = new
00380 QVPropertyContainerLink(qvp_orig,prop_orig,qvp_dest,prop_dest,link_type);
00381 qvp_orig->outputLinks[prop_orig].push_back(link);
00382 qvp_dest->inputLinks[prop_dest] = link;
00383 qvp_dest->link_flags[prop_dest] |= linkedInputFlag;
00384 qvp_orig->link_flags[prop_orig] |= linkedOutputFlag;
00385
00386
00387
00388 this->RWLock.lockForWrite();
00389 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00390 this->RWLock.unlock();
00391
00392 return TRUE;
00393 }
00394 }
00395
00396 void QVPropertyContainer::linkProperty(QVPropertyContainer *container, LinkType linkType)
00397 {
00398 QList<QString> localProper = getPropertyList();
00399 QList<QString> inputProper = container->getPropertyList();
00400
00401 qSort(localProper.begin(), localProper.end());
00402 qSort(inputProper.begin(), inputProper.end());
00403
00404 int i=0, l=0;
00405 while ( (i < inputProper.size()) && (l < localProper.size()) )
00406 {
00407 QString localName = localProper[l];
00408 QString inputName = inputProper[i];
00409 if (
00410 (localName == inputName) &&
00411 (getPropertyType(localName) == container->getPropertyType(inputName)) &&
00412 (io_flags[localName] & outputFlag) &&
00413 (container->io_flags[inputName] & inputFlag) &&
00414 (!(io_flags[localName] & internalProp)) &&
00415 (!(container->io_flags[inputName] & internalProp))
00416 )
00417 linkProperty(localProper[l], container, inputProper[i], linkType);
00418
00419 if(localName <= inputName) l++;
00420 if(localName >= inputName) i++;
00421 }
00422 }
00423
00424 void QVPropertyContainer::unlink()
00425 {
00426 QMapIterator<QString, QVPropertyContainerLink*> i_in(inputLinks);
00427 while (i_in.hasNext()) {
00428 i_in.next();
00429 QVPropertyContainerLink *link = i_in.value();
00430 link->markedForDeletion = TRUE;
00431
00432
00433 link->SyncSemaphoreIn.release();
00434 }
00435
00436 QMapIterator<QString, QList<QVPropertyContainerLink*> >i_out(outputLinks);
00437 while (i_out.hasNext()) {
00438 i_out.next();
00439 QListIterator<QVPropertyContainerLink*> j_out(i_out.value());
00440 while(j_out.hasNext()) {
00441 QVPropertyContainerLink *link = j_out.next();
00442 link->markedForDeletion = TRUE;
00443
00444
00445 link->SyncSemaphoreOut.release();
00446 }
00447 }
00448 }
00449
00450 void QVPropertyContainer::readInputProperties()
00451 {
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 QMutableMapIterator<QString, QVPropertyContainerLink*> i(inputLinks);
00463 while (i.hasNext()) {
00464 i.next();
00465 QVPropertyContainerLink *link = i.value();
00466 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00467 link->SyncSemaphoreOut.acquire();
00468 }
00469 link->qvp_orig->RWLock.lockForRead();
00470
00471 this->variants[link->prop_dest] = link->qvp_orig->safelyCopiedVariants[link->prop_orig];
00472 link->qvp_orig->RWLock.unlock();
00473 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00474 link->SyncSemaphoreIn.release();
00475 }
00476
00477 if(link->markedForDeletion) {
00478 i.remove();
00479 delete link;
00480 }
00481 }
00482 }
00483
00484 void QVPropertyContainer::writeOutputProperties()
00485 {
00486 QMutableMapIterator<QString, QList<QVPropertyContainerLink*> >i(outputLinks);
00487
00488
00489
00490
00491 while (i.hasNext()) {
00492 i.next();
00493 QListIterator<QVPropertyContainerLink*> j(i.value());
00494 while(j.hasNext()) {
00495 QVPropertyContainerLink *link = j.next();
00496 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00497 link->SyncSemaphoreIn.acquire();
00498 }
00499 }
00500 }
00501
00502
00503
00504 i.toFront();
00505 this->RWLock.lockForWrite();
00506 while (i.hasNext()) {
00507 i.next();
00508 QString prop_orig = i.key();
00509 safelyCopiedVariants[prop_orig] = variants[prop_orig];
00510 }
00511 this->RWLock.unlock();
00512
00513
00514
00515
00516 i.toFront();
00517 while (i.hasNext()) {
00518 i.next();
00519 QMutableListIterator<QVPropertyContainerLink*> j(i.value());
00520 while(j.hasNext()) {
00521 QVPropertyContainerLink *link = j.next();
00522 if(link->link_type == SynchronousLink and not link->markedForDeletion) {
00523 link->SyncSemaphoreOut.release();
00524 }
00525
00526 if(link->markedForDeletion) {
00527 j.remove();
00528 delete link;
00529 if(i.value().isEmpty()) {
00530 i.remove();
00531 break;
00532 }
00533 }
00534 }
00535 }
00536 }
00537
00538 void QVPropertyContainer::setLastError(QString str) const
00539 { errorString = str; }
00540
00541 bool QVPropertyContainer::areSynchronized(const QList<QVPropertyContainer> conts)
00542 {
00543 QVDisjointSet dSet(conts.size());
00544
00545 for (int i = 0; i < conts.size(); i++)
00546 for (int j = i+1; j < conts.size(); j++)
00547 {
00548 bool find = false;
00549
00550 if (conts.at(i).getId() == conts.at(j).getId())
00551 {
00552 dSet.unify(i, j);
00553 find = true;
00554 }
00555 if (!find)
00556 {
00557 const QMap<QString, QVPropertyContainerLink* > inLinksI = conts.at(i).getInputLinks();
00558 foreach(QVPropertyContainerLink* proConLink, inLinksI.values())
00559 if ( (proConLink->qvp_orig->getId() == conts.at(j).getId()) &&
00560 (proConLink->link_type == SynchronousLink) )
00561 {
00562 dSet.unify(i, j);
00563 find = true;
00564 break;
00565 }
00566 }
00567 if (!find)
00568 {
00569 const QMap<QString, QVPropertyContainerLink* > inLinksJ = conts.at(j).getInputLinks();
00570 foreach(QVPropertyContainerLink* proConLink, inLinksJ.values())
00571 if ( (proConLink->qvp_orig->getId() == conts.at(i).getId()) &&
00572 (proConLink->link_type == SynchronousLink) )
00573 {
00574 dSet.unify(i, j);
00575 break;
00576 }
00577 }
00578 }
00579
00580 return (dSet.numberOfSets() == 1);
00581 }
00582
00583 template <> bool QVPropertyContainer::parseArgument<bool>(const QString parameter, const QString value)
00584 {
00585 if (value.toLower() == "true" || value.toLower() == "false")
00586 {
00587
00588 setPropertyValue<bool>(parameter,value.toLower() == "true");
00589 return TRUE;
00590 }
00591 else {
00592 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00593 ": value " + value +
00594 " is not a valid boolean value for parameter " +
00595 parameter + ".\n";
00596 return FALSE;
00597 }
00598 }
00599
00600 template <> bool QVPropertyContainer::parseArgument<int>(const QString parameter, const QString value)
00601 {
00602 bool okInt;
00603 int intValue = value.toInt(&okInt);
00604 if(not okInt)
00605 {
00606 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00607 ": value " + value +
00608 " is not a valid integer value for parameter " +
00609 parameter + ".\n";
00610 return FALSE;
00611 }
00612
00613 setPropertyValue<int>(parameter,intValue);
00614 return TRUE;
00615 }
00616
00617 template <> bool QVPropertyContainer::parseArgument<double>(const QString parameter, const QString value)
00618 {
00619 bool okDouble;
00620 double doubleValue = value.toDouble(&okDouble);
00621 if(not okDouble)
00622 {
00623 errorString = "QVPropertyContainer::parseArgument(): holder " + getName() +
00624 ": value " + value +
00625 " is not a valid double value for parameter " +
00626 parameter + ".\n";
00627 return FALSE;
00628 }
00629
00630 setPropertyValue<double>(parameter,doubleValue);
00631 return TRUE;
00632 }
00633
00634 template <> bool QVPropertyContainer::parseArgument<QString>(const QString parameter, const QString value)
00635 {
00636
00637 setPropertyValue<QString>(parameter,value);
00638 return TRUE;
00639 }