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