xmlRpcTreeItem.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2015, C. Dornhege, University of Freiburg
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *  * Redistributions of source code must retain the above copyright notice, this
00009  *    list of conditions and the following disclaimer.
00010  *  * Redistributions in binary form must reproduce the above copyright notice, 
00011  *    this list of conditions and the following disclaimer in the documentation 
00012  *    and/or other materials provided with the distribution.
00013  *  * Neither the name of the University of Freiburg nor the names
00014  *    of its contributors may be used to endorse or promote products derived from
00015  *    this software without specific prior written permission.
00016  * 
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00023  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00024  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00025  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00026  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00029 #include "qt_paramedit/xmlRpcTreeItem.h"
00030 #include <QDateTime>
00031 
00032 #include <boost/foreach.hpp>
00033 #define forEach BOOST_FOREACH
00034 
00035 XmlRpcTreeItem::XmlRpcTreeItem(XmlRpc::XmlRpcValue* data, XmlRpcTreeItem* parent, const std::string & path, 
00036       ros::NodeHandle* nh)
00037    : _data(data), _parent(parent), _path(path), _nh(nh)
00038 {
00039    ROS_ASSERT(_nh != NULL);
00040 
00041    createChildren();
00042 }
00043 
00044 XmlRpcTreeItem::~XmlRpcTreeItem()
00045 {
00046    forEach(XmlRpcTreeItem* child, _children)
00047       delete child;
00048    _children.clear();
00049 }
00050 
00055 unsigned int XmlRpcTreeItem::childCount() const 
00056 { 
00057    if(_children.size() > 0)
00058       return _children.size(); 
00059 
00060    return 0;
00061 }
00062 
00063 int XmlRpcTreeItem::childIndexOf(const XmlRpcTreeItem* child) const
00064 {
00065    int index = -1;
00066    for(unsigned int i = 0; i < _children.size(); i++) {
00067       if(child == _children[i]) {
00068          index = i;
00069          break;
00070       }
00071    }
00072    return index;
00073 }
00074 
00075 int XmlRpcTreeItem::row() const
00076 {
00077    if(_parent) {
00078       return _parent->childIndexOf(this);
00079    }
00080 
00081    // root at index 0
00082    return 0;
00083 }
00084 
00085 QVariant XmlRpcTreeItem::xmlToVariant(XmlRpc::XmlRpcValue & val) const
00086 {
00087    switch(val.getType()) {
00088       case XmlRpc::XmlRpcValue::TypeBoolean:
00089          return QVariant( (bool)val );
00090          break;
00091       case XmlRpc::XmlRpcValue::TypeInt:
00092          return QVariant( (int)val );
00093          break;
00094       case XmlRpc::XmlRpcValue::TypeDouble:
00095          return QVariant( (double)val );
00096          break;
00097       case XmlRpc::XmlRpcValue::TypeString:
00098          return QVariant( ((std::string)val).c_str() );
00099          break;
00100       case XmlRpc::XmlRpcValue::TypeDateTime:
00101          {
00102             ROS_WARN_THROTTLE(1.0, "Accessing TypeDateTime is untested.");
00103             struct tm time = (struct tm)val;
00104             int ms = 0;
00105             if(time.tm_sec > 59) // might be > 59 for leap seconds, Qt wants 0-59
00106                ms = 999;
00107 
00108             return QVariant( QDateTime(
00109                      /*
00110                       *       tm_mday   day of the month        1-31
00111                       *       tm_mon    months since January    0-11
00112                       *       tm_year   years since 1900
00113                       */
00114                      QDate(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday),
00115                      /*
00116                       *       tm_sec    seconds after the minute        0-61
00117                       *       tm_min    minutes after the hour  0-59
00118                       *       tm_hour   hours since midnight    0-23
00119                       */
00120                      QTime(time.tm_hour, time.tm_min, time.tm_sec, ms)));
00121             break;
00122          }
00123       case XmlRpc::XmlRpcValue::TypeBase64:
00124          {
00125             ROS_WARN_THROTTLE(1.0, "Accessing TypeBase64 is untested.");
00126             XmlRpc::XmlRpcValue::BinaryData & bd = (XmlRpc::XmlRpcValue::BinaryData&)val;
00127             QByteArray ba;
00128             for(std::vector<char>::iterator it = bd.begin(); it != bd.end(); it++)
00129                ba.append(*it);
00130             return QVariant(ba);
00131             break;
00132          }
00133       default:
00134          return QVariant();
00135    }
00136 
00137    return QVariant();
00138 }
00139 
00140 QVariant XmlRpcTreeItem::data(int row, int column) const
00141 {
00142    // this node always has to be a map!
00143 
00144    if(column > 1)
00145       return QVariant();
00146 
00147    // get the row'th entry
00148    if(_data->getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00149       int count = 0;
00150       for(XmlRpc::XmlRpcValue::iterator it = _data->begin(); it != _data->end(); it++) {
00151          if(count == row) {   // at row'th entry
00152             if(column == 0) { // get the rows'th key
00153                return it->first.c_str();
00154             }
00155             if(column == 1) {
00156                XmlRpc::XmlRpcValue & val = it->second;
00157                return xmlToVariant(val);
00158             }
00159          }
00160          count++;
00161       }
00162    } else if(_data->getType() == XmlRpc::XmlRpcValue::TypeArray) {
00163       if(column == 0) {
00164          return QString("[%1]").arg(row);
00165       } else {
00166          XmlRpc::XmlRpcValue & val = (*_data)[row];
00167          return xmlToVariant(val);
00168       }
00169    }
00170 
00171    // nothing found 
00172    return QVariant();
00173 }
00174 
00175 bool XmlRpcTreeItem::isBool(int row, int column) const
00176 {
00177    // this node always has to be a map!
00178 
00179    if(column != 1)
00180       return false;
00181 
00182    // get the row'th entry
00183    if(_data->getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00184       int count = 0;
00185       for(XmlRpc::XmlRpcValue::iterator it = _data->begin(); it != _data->end(); it++) {
00186          if(count == row) {   // at row'th entry
00187             XmlRpc::XmlRpcValue & val = it->second;
00188             if(val.getType() == XmlRpc::XmlRpcValue::TypeBoolean)
00189                return true;
00190             else 
00191                return false;
00192          }
00193          count++;
00194       }
00195    } else if(_data->getType() == XmlRpc::XmlRpcValue::TypeArray) {
00196       XmlRpc::XmlRpcValue & val = (*_data)[row];
00197       if(val.getType() == XmlRpc::XmlRpcValue::TypeBoolean)
00198          return true;
00199       else 
00200          return false;
00201    }
00202 
00203    // nothing found 
00204    return false;
00205 }
00206 
00207 bool XmlRpcTreeItem::setData(QVariant val)
00208 {
00209    XmlRpc::XmlRpcValue::Type type = _data->getType();
00210    if(type == XmlRpc::XmlRpcValue::TypeStruct || type == XmlRpc::XmlRpcValue::TypeArray 
00211          || type == XmlRpc::XmlRpcValue::TypeInvalid) {
00212       return false;
00213    }
00214 
00215    bool setXmlOK = false;
00216    switch(type) {
00217       case XmlRpc::XmlRpcValue::TypeBoolean:
00218          if(!val.canConvert(QVariant::Bool)) {
00219             ROS_WARN("XmlRpcValue TypeBoolean -- setData cannot convert from QVariant type %d.", val.type());
00220             break;
00221          }
00222          ROS_DEBUG("Setting bool param.");
00223          (bool&)(*_data) = val.toBool();
00224          setXmlOK = true;
00225          break;
00226       case XmlRpc::XmlRpcValue::TypeInt:
00227          {
00228             if(!val.canConvert(QVariant::Int)) {
00229                ROS_WARN("XmlRpcValue TypeInt -- setData cannot convert from QVariant type %d.", val.type());
00230                break;
00231             }
00232             bool ok = false;
00233             int iVal =  val.toInt(&ok);
00234             if(ok) {
00235                ROS_DEBUG("Setting int param.");
00236                (int&)(*_data) = iVal;
00237                setXmlOK = true;
00238             }
00239             break;
00240          }
00241       case XmlRpc::XmlRpcValue::TypeDouble:
00242          {
00243             if(!val.canConvert(QVariant::Double)) {
00244                ROS_WARN("XmlRpcValue TypeDouble -- setData cannot convert from QVariant type %d.", val.type());
00245                break;
00246             }
00247             // although e.g. strings can be converted to double in principle, the conversion of "hallo" still fails
00248             // -> check via OK and only update _data if the conversion succeeded.
00249             bool ok = false;
00250             double dVal = val.toDouble(&ok);
00251             if(ok) {
00252                ROS_DEBUG("Setting double param.");
00253                (double&)(*_data) = dVal;
00254                setXmlOK = true;
00255             }
00256             break;
00257          }
00258       case XmlRpc::XmlRpcValue::TypeString:
00259          if(!val.canConvert(QVariant::String)) {
00260             ROS_WARN("XmlRpcValue TypeString -- setData cannot convert from QVariant type %d.", val.type());
00261             break;
00262          }
00263          ROS_DEBUG("Setting string param.");
00264          (std::string&)(*_data) = qPrintable(val.toString());
00265          setXmlOK = true;
00266          break;
00267       case XmlRpc::XmlRpcValue::TypeDateTime:
00268          {
00269             ROS_WARN_THROTTLE(1.0, "Accessing TypeDateTime is untested.");
00270             if(!val.canConvert(QVariant::DateTime)) {
00271                ROS_WARN("XmlRpcValue TypeDateTime -- setData cannot convert from QVariant type %d.", val.type());
00272                break;
00273             }
00274             QDateTime dt = val.toDateTime();
00275             if(dt.isValid()) {
00276                ROS_DEBUG("Setting datetime param.");
00277                struct tm time;
00278                time.tm_year = dt.date().year() - 1900;
00279                time.tm_mon = dt.date().month() - 1;
00280                time.tm_mday = dt.date().day();
00281                time.tm_hour = dt.time().hour();
00282                time.tm_min = dt.time().minute();
00283                time.tm_sec = dt.time().second();
00284                time.tm_wday = dt.date().dayOfWeek() - 1;
00285                time.tm_yday = dt.date().dayOfYear() - 1;
00286                time.tm_isdst = -1;
00287                time.tm_zone = "";
00288                time.tm_gmtoff = 0;
00289 
00290                (struct tm &)(*_data) = time;
00291                setXmlOK = true;
00292             }
00293             break;
00294          }
00295       case XmlRpc::XmlRpcValue::TypeBase64:
00296          {
00297             ROS_WARN_THROTTLE(1.0, "Accessing TypeBase64 is untested.");
00298             if(!val.canConvert(QVariant::ByteArray)) {
00299                ROS_WARN("XmlRpcValue TypeBase64 -- setData cannot convert from QVariant type %d.", val.type());
00300                break;
00301             }
00302             QByteArray ba = val.toByteArray();
00303             XmlRpc::XmlRpcValue::BinaryData bd;
00304             for(int i = 0; i < ba.size(); i++) {
00305                bd.push_back(ba.at(i));
00306             }
00307             ROS_DEBUG("Setting base64 param.");
00308             (XmlRpc::XmlRpcValue::BinaryData &)(*_data) = bd;
00309             break;
00310          }
00311       default:
00312          return false;
00313    }
00314    if(setXmlOK) {
00315       if(!_path.empty()) {
00316          ROS_DEBUG("Setting param type %d on server path %s.", _data->getType(), _path.c_str());
00317          _nh->setParam(_path, *_data);
00318       } else {
00319          _parent->setParam();
00320       }
00321    }
00322 
00323    return true;
00324 }
00325 
00326 void XmlRpcTreeItem::setParam()
00327 {
00328    ROS_ASSERT(_data->getType() == XmlRpc::XmlRpcValue::TypeArray);
00329 
00330    ROS_DEBUG("Setting param type %d on server path %s.", _data->getType(), _path.c_str());
00331    if(!_path.empty())
00332       _nh->setParam(_path, *_data);
00333 }
00334 
00335 void XmlRpcTreeItem::createChildren()
00336 {
00337    // only maps and arrays have children
00338 
00339    if(_data->getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00340       for(XmlRpc::XmlRpcValue::iterator it = _data->begin(); it != _data->end(); it++) {
00341          addChild(it->first, &it->second);
00342       }
00343    } else if(_data->getType() == XmlRpc::XmlRpcValue::TypeArray) {
00344       for(int i = 0; i < _data->size(); i++) {
00345          addChild("", & ((*_data)[i]));
00346       }
00347    }
00348 }
00349 
00350 void XmlRpcTreeItem::addChild(const std::string & name, XmlRpc::XmlRpcValue* childData)
00351 {
00352    std::string path = ros::names::append(this->_path, name);
00353    if(name.empty())
00354       path = name;   // no path
00355    XmlRpcTreeItem* child = new XmlRpcTreeItem(childData, this, path, _nh);
00356    _children.push_back(child);
00357 }
00358 


qt_paramedit
Author(s): Christian Dornhege
autogenerated on Fri Aug 28 2015 12:50:12