$search
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