xmlRpcTreeItem.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, 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 "rxparamedit/xmlRpcTreeItem.h"
00030 #include <QDateTime>
00031 
00032 XmlRpcTreeItem::XmlRpcTreeItem(XmlRpc::XmlRpcValue* data, XmlRpcTreeItem* parent, const std::string & path, 
00033       ros::NodeHandle* nh)
00034    : _data(data), _parent(parent), _path(path), _nh(nh)
00035 {
00036    ROS_ASSERT(_nh != NULL);
00037 
00038    createChildren();
00039 }
00040 
00041 XmlRpcTreeItem::~XmlRpcTreeItem()
00042 {
00043    forEach(XmlRpcTreeItem* child, _children)
00044       delete child;
00045    _children.clear();
00046 }
00047 
00052 unsigned int XmlRpcTreeItem::childCount() const 
00053 { 
00054    if(_children.size() > 0)
00055       return _children.size(); 
00056 
00057    return 0;
00058 }
00059 
00060 int XmlRpcTreeItem::childIndexOf(const XmlRpcTreeItem* child) const
00061 {
00062    int index = -1;
00063    for(unsigned int i = 0; i < _children.size(); i++) {
00064       if(child == _children[i]) {
00065          index = i;
00066          break;
00067       }
00068    }
00069    return index;
00070 }
00071 
00072 int XmlRpcTreeItem::row() const
00073 {
00074    if(_parent) {
00075       return _parent->childIndexOf(this);
00076    }
00077 
00078    // root at index 0
00079    return 0;
00080 }
00081 
00082 QVariant XmlRpcTreeItem::xmlToVariant(XmlRpc::XmlRpcValue & val) const
00083 {
00084    switch(val.getType()) {
00085       case XmlRpc::XmlRpcValue::TypeBoolean:
00086          return QVariant( (bool)val );
00087          break;
00088       case XmlRpc::XmlRpcValue::TypeInt:
00089          return QVariant( (int)val );
00090          break;
00091       case XmlRpc::XmlRpcValue::TypeDouble:
00092          return QVariant( (double)val );
00093          break;
00094       case XmlRpc::XmlRpcValue::TypeString:
00095          return QVariant( ((std::string)val).c_str() );
00096          break;
00097       case XmlRpc::XmlRpcValue::TypeDateTime:
00098          {
00099             ROS_WARN_THROTTLE(1.0, "Accessing TypeDateTime is untested.");
00100             struct tm time = (struct tm)val;
00101             int ms = 0;
00102             if(time.tm_sec > 59) // might be > 59 for leap seconds, Qt wants 0-59
00103                ms = 999;
00104 
00105             return QVariant( QDateTime(
00106                      /*
00107                       *       tm_mday   day of the month        1-31
00108                       *       tm_mon    months since January    0-11
00109                       *       tm_year   years since 1900
00110                       */
00111                      QDate(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday),
00112                      /*
00113                       *       tm_sec    seconds after the minute        0-61
00114                       *       tm_min    minutes after the hour  0-59
00115                       *       tm_hour   hours since midnight    0-23
00116                       */
00117                      QTime(time.tm_hour, time.tm_min, time.tm_sec, ms)));
00118             break;
00119          }
00120       case XmlRpc::XmlRpcValue::TypeBase64:
00121          {
00122             ROS_WARN_THROTTLE(1.0, "Accessing TypeBase64 is untested.");
00123             XmlRpc::XmlRpcValue::BinaryData & bd = (XmlRpc::XmlRpcValue::BinaryData&)val;
00124             QByteArray ba;
00125             for(std::vector<char>::iterator it = bd.begin(); it != bd.end(); it++)
00126                ba.append(*it);
00127             return QVariant(ba);
00128             break;
00129          }
00130       default:
00131          return QVariant();
00132    }
00133 
00134    return QVariant();
00135 }
00136 
00137 QVariant XmlRpcTreeItem::data(int row, int column) const
00138 {
00139    // this node always has to be a map!
00140 
00141    if(column > 1)
00142       return QVariant();
00143 
00144    // get the row'th entry
00145    if(_data->getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00146       int count = 0;
00147       for(XmlRpc::XmlRpcValue::iterator it = _data->begin(); it != _data->end(); it++) {
00148          if(count == row) {   // at row'th entry
00149             if(column == 0) { // get the rows'th key
00150                return it->first.c_str();
00151             }
00152             if(column == 1) {
00153                XmlRpc::XmlRpcValue & val = it->second;
00154                return xmlToVariant(val);
00155             }
00156          }
00157          count++;
00158       }
00159    } else if(_data->getType() == XmlRpc::XmlRpcValue::TypeArray) {
00160       if(column == 0) {
00161          return QString("[%1]").arg(row);
00162       } else {
00163          XmlRpc::XmlRpcValue & val = (*_data)[row];
00164          return xmlToVariant(val);
00165       }
00166    }
00167   
00168    // nothing found 
00169    return QVariant();
00170 }
00171 
00172 bool XmlRpcTreeItem::isBool(int row, int column) const
00173 {
00174    // this node always has to be a map!
00175 
00176    if(column != 1)
00177       return false;
00178 
00179    // get the row'th entry
00180    if(_data->getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00181       int count = 0;
00182       for(XmlRpc::XmlRpcValue::iterator it = _data->begin(); it != _data->end(); it++) {
00183          if(count == row) {   // at row'th entry
00184             XmlRpc::XmlRpcValue & val = it->second;
00185             if(val.getType() == XmlRpc::XmlRpcValue::TypeBoolean)
00186                return true;
00187             else 
00188                return false;
00189          }
00190          count++;
00191       }
00192    } else if(_data->getType() == XmlRpc::XmlRpcValue::TypeArray) {
00193       XmlRpc::XmlRpcValue & val = (*_data)[row];
00194       if(val.getType() == XmlRpc::XmlRpcValue::TypeBoolean)
00195          return true;
00196       else 
00197          return false;
00198    }
00199   
00200    // nothing found 
00201    return false;
00202 }
00203 
00204 bool XmlRpcTreeItem::setData(QVariant val)
00205 {
00206    XmlRpc::XmlRpcValue::Type type = _data->getType();
00207    if(type == XmlRpc::XmlRpcValue::TypeStruct || type == XmlRpc::XmlRpcValue::TypeArray 
00208          || type == XmlRpc::XmlRpcValue::TypeInvalid) {
00209       return false;
00210    }
00211 
00212    bool setXmlOK = false;
00213    switch(type) {
00214       case XmlRpc::XmlRpcValue::TypeBoolean:
00215          if(!val.canConvert(QVariant::Bool)) {
00216             ROS_WARN("XmlRpcValue TypeBoolean -- setData cannot convert from QVariant type %d.", val.type());
00217             break;
00218          }
00219          ROS_DEBUG("Setting bool param.");
00220          (bool&)(*_data) = val.toBool();
00221          setXmlOK = true;
00222          break;
00223       case XmlRpc::XmlRpcValue::TypeInt:
00224          {
00225             if(!val.canConvert(QVariant::Int)) {
00226                ROS_WARN("XmlRpcValue TypeInt -- setData cannot convert from QVariant type %d.", val.type());
00227                break;
00228             }
00229             bool ok = false;
00230             int iVal =  val.toInt(&ok);
00231             if(ok) {
00232                ROS_DEBUG("Setting int param.");
00233                (int&)(*_data) = iVal;
00234                setXmlOK = true;
00235             }
00236             break;
00237          }
00238       case XmlRpc::XmlRpcValue::TypeDouble:
00239          {
00240             if(!val.canConvert(QVariant::Double)) {
00241                ROS_WARN("XmlRpcValue TypeDouble -- setData cannot convert from QVariant type %d.", val.type());
00242                break;
00243             }
00244             // although e.g. strings can be converted to double in principle, the conversion of "hallo" still fails
00245             // -> check via OK and only update _data if the conversion succeeded.
00246             bool ok = false;
00247             double dVal = val.toDouble(&ok);
00248             if(ok) {
00249                ROS_DEBUG("Setting double param.");
00250                (double&)(*_data) = dVal;
00251                setXmlOK = true;
00252             }
00253             break;
00254          }
00255       case XmlRpc::XmlRpcValue::TypeString:
00256          if(!val.canConvert(QVariant::String)) {
00257             ROS_WARN("XmlRpcValue TypeString -- setData cannot convert from QVariant type %d.", val.type());
00258             break;
00259          }
00260          ROS_DEBUG("Setting string param.");
00261          (std::string&)(*_data) = qPrintable(val.toString());
00262          setXmlOK = true;
00263          break;
00264       case XmlRpc::XmlRpcValue::TypeDateTime:
00265          {
00266             ROS_WARN_THROTTLE(1.0, "Accessing TypeDateTime is untested.");
00267             if(!val.canConvert(QVariant::DateTime)) {
00268                ROS_WARN("XmlRpcValue TypeDateTime -- setData cannot convert from QVariant type %d.", val.type());
00269                break;
00270             }
00271             QDateTime dt = val.toDateTime();
00272             if(dt.isValid()) {
00273                ROS_DEBUG("Setting datetime param.");
00274                struct tm time;
00275                time.tm_year = dt.date().year() - 1900;
00276                time.tm_mon = dt.date().month() - 1;
00277                time.tm_mday = dt.date().day();
00278                time.tm_hour = dt.time().hour();
00279                time.tm_min = dt.time().minute();
00280                time.tm_sec = dt.time().second();
00281                time.tm_wday = dt.date().dayOfWeek() - 1;
00282                time.tm_yday = dt.date().dayOfYear() - 1;
00283                time.tm_isdst = -1;
00284                time.tm_zone = "";
00285                time.tm_gmtoff = 0;
00286                
00287                (struct tm &)(*_data) = time;
00288                setXmlOK = true;
00289             }
00290             break;
00291          }
00292       case XmlRpc::XmlRpcValue::TypeBase64:
00293          {
00294             ROS_WARN_THROTTLE(1.0, "Accessing TypeBase64 is untested.");
00295             if(!val.canConvert(QVariant::ByteArray)) {
00296                ROS_WARN("XmlRpcValue TypeBase64 -- setData cannot convert from QVariant type %d.", val.type());
00297                break;
00298             }
00299             QByteArray ba = val.toByteArray();
00300             XmlRpc::XmlRpcValue::BinaryData bd;
00301             for(int i = 0; i < ba.size(); i++) {
00302                bd.push_back(ba.at(i));
00303             }
00304             ROS_DEBUG("Setting base64 param.");
00305             (XmlRpc::XmlRpcValue::BinaryData &)(*_data) = bd;
00306             break;
00307          }
00308       default:
00309          return false;
00310    }
00311    if(setXmlOK) {
00312       if(!_path.empty()) {
00313          ROS_DEBUG("Setting param type %d on server path %s.", _data->getType(), _path.c_str());
00314          _nh->setParam(_path, *_data);
00315       } else {
00316          _parent->setParam();
00317       }
00318    }
00319 
00320    return true;
00321 }
00322 
00323 void XmlRpcTreeItem::setParam()
00324 {
00325    ROS_ASSERT(_data->getType() == XmlRpc::XmlRpcValue::TypeArray);
00326 
00327    ROS_DEBUG("Setting param type %d on server path %s.", _data->getType(), _path.c_str());
00328    if(!_path.empty())
00329       _nh->setParam(_path, *_data);
00330 }
00331 
00332 void XmlRpcTreeItem::createChildren()
00333 {
00334    // only maps and arrays have children
00335 
00336    if(_data->getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00337       for(XmlRpc::XmlRpcValue::iterator it = _data->begin(); it != _data->end(); it++) {
00338          addChild(it->first, &it->second);
00339       }
00340    } else if(_data->getType() == XmlRpc::XmlRpcValue::TypeArray) {
00341       for(int i = 0; i < _data->size(); i++) {
00342          addChild("", & ((*_data)[i]));
00343       }
00344    }
00345 }
00346 
00347 void XmlRpcTreeItem::addChild(const std::string & name, XmlRpc::XmlRpcValue* childData)
00348 {
00349    std::string path = ros::names::append(this->_path, name);
00350    if(name.empty())
00351       path = name;   // no path
00352    XmlRpcTreeItem* child = new XmlRpcTreeItem(childData, this, path, _nh);
00353    _children.push_back(child);
00354 }
00355 


rxparamedit
Author(s): Christian Dornhege
autogenerated on Mon Oct 6 2014 00:08:57