00001 #include <QFile>
00002 #include <QStringList>
00003 #include "rqt_mrta/config/config.h"
00004 #include "rqt_mrta/config/param_factory.h"
00005 #include "utilities/exception.h"
00006
00007 namespace rqt_mrta
00008 {
00009 namespace config
00010 {
00011 Config::Config(QObject* parent) : AbstractConfig(parent) {}
00012
00013 Config::~Config()
00014 {
00015 clearArrays();
00016
00017
00018
00019
00020
00021
00022
00023
00024 params_.clear();
00025 }
00026
00027 QString Config::getId() const { return id_; }
00028
00029 void Config::setId(const QString& id)
00030 {
00031 if (id != id_)
00032 {
00033 id_ = id;
00034 emit idChanged(id);
00035 emit changed();
00036 }
00037 }
00038
00039 QVector<ParamInterface*> Config::getChildren() const { return params_; }
00040
00041 ParamInterface* Config::getChild(size_t index) const { return params_[index]; }
00042
00043 ParamInterface* Config::getParam(const QString& relative_name) const
00044 {
00045 QStringList names(relative_name.split("/"));
00046 QString root_name(names[0]);
00047 if (root_name.isEmpty())
00048 {
00049 return NULL;
00050 }
00051 names.removeFirst();
00052 for (size_t i(0); i < params_.count(); i++)
00053 {
00054 if (params_[i]->getName() == root_name)
00055 {
00056 return !names.isEmpty() ? params_[i]->getParam(names.join("/"))
00057 : params_[i];
00058 }
00059 }
00060 return NULL;
00061 }
00062
00063 void Config::addParam(ParamInterface* param)
00064 {
00065 params_.append(param);
00066 connect(param, SIGNAL(changed()), this, SIGNAL(changed()));
00067 connect(param, SIGNAL(nameChanged(const QString&, const QString&)), this,
00068 SIGNAL(nameChanged(const QString&, const QString&)));
00069 connect(param, SIGNAL(typeChanged(const QString&, const QMetaType::Type&)),
00070 this, SIGNAL(typeChanged(const QString&, const QMetaType::Type&)));
00071 connect(param, SIGNAL(valueChanged(const QString&, const QVariant&)), this,
00072 SIGNAL(valueChanged(const QString&, const QVariant&)));
00073 connect(param, SIGNAL(defaultValueChanged(const QString&, const QVariant&)),
00074 this, SIGNAL(defaultValueChanged(const QString&, const QVariant&)));
00075 connect(param, SIGNAL(toolTipChanged(const QString&, const QString&)), this,
00076 SIGNAL(toolTipChanged(const QString&, const QString&)));
00077 connect(param, SIGNAL(added(const QString&)), this,
00078 SIGNAL(added(const QString&)));
00079 connect(param, SIGNAL(removed(const QString&)), this,
00080 SIGNAL(removed(const QString&)));
00081 connect(param, SIGNAL(cleared(const QString&)), this,
00082 SIGNAL(cleared(const QString&)));
00083 connect(param, SIGNAL(destroyed()), this, SLOT(paramDestroyed()));
00084 emit added(param->getFullName());
00085 emit changed();
00086 }
00087
00088 void Config::removeParam(const QString& full_name)
00089 {
00090 ParamInterface* param = getParam(full_name);
00091 if (param)
00092 {
00093 ParamInterface* parent = param->getParentParam();
00094 if (parent)
00095 {
00096 parent->removeParam(param->getName());
00097 }
00098 else
00099 {
00100 size_t index(params_.indexOf(param));
00101 if (index == -1)
00102 {
00103 return;
00104 }
00105
00106
00107
00108
00109
00110 params_.remove(index);
00111 emit removed(full_name);
00112 emit changed();
00113 }
00114 }
00115 }
00116
00117 void Config::clearParams()
00118 {
00119 if (!params_.isEmpty())
00120 {
00121 for (size_t index(0); index < params_.count(); index++)
00122 {
00123
00124
00125
00126
00127
00128 }
00129 params_.clear();
00130 emit cleared("");
00131 emit changed();
00132 }
00133 }
00134
00135 void Config::clearParams(const QString& full_name)
00136 {
00137 if (!full_name.isEmpty())
00138 {
00139 ParamInterface* param = getParam(full_name);
00140 param->clearParams();
00141 }
00142 else if (!params_.isEmpty())
00143 {
00144 clearParams();
00145 }
00146 }
00147
00148 bool Config::contains(const QString& full_name) const
00149 {
00150 QStringList names(full_name.split("/"));
00151 for (size_t index(0); index < params_.count(); index++)
00152 {
00153 if (params_[index]->getName() == names[0])
00154 {
00155 names.removeFirst();
00156 return names.isEmpty() || params_[index]->contains(names.join("/"));
00157 }
00158 }
00159 return false;
00160 }
00161
00162 size_t Config::count() const { return params_.count(); }
00163
00164 size_t Config::count(const QString& full_name) const
00165 {
00166 if (full_name.isEmpty())
00167 {
00168 return params_.count();
00169 }
00170 ParamInterface* param = getParam(full_name);
00171 return param->count();
00172 }
00173
00174 bool Config::isEmpty() const { return params_.isEmpty(); }
00175
00176 bool Config::isEmpty(const QString& full_name) const
00177 {
00178 if (full_name.isEmpty())
00179 {
00180 return params_.isEmpty();
00181 }
00182 ParamInterface* param = getParam(full_name);
00183 return param->isEmpty();
00184 }
00185
00186 void Config::save(QSettings& settings) const
00187 {
00188 settings.setValue("id", id_);
00189 for (size_t index(0); index < params_.count(); ++index)
00190 {
00191 settings.beginGroup(params_[index]->getGroupName() + "_" +
00192 QString::number(index));
00193 params_[index]->save(settings);
00194 settings.endGroup();
00195 }
00196 }
00197
00198 void Config::load(QSettings& settings)
00199 {
00200 setId(settings.value("id").toString());
00201 QStringList groups(Params::sortGroups(settings.childGroups()));
00202 clearParams();
00203 for (size_t index(0); index < groups.count(); index++)
00204 {
00205 ParamInterface* param = ParamFactory::newInstance(groups[index]);
00206 addParam(param);
00207 settings.beginGroup(param->getGroupName() + "_" + QString::number(index));
00208 param->load(settings);
00209 settings.endGroup();
00210 }
00211 }
00212
00213 void Config::reset()
00214 {
00215 for (size_t index(0); index < params_.count(); index++)
00216 {
00217 params_[index]->reset();
00218 }
00219 }
00220
00221 void Config::write(QDataStream& stream) const
00222 {
00223 stream << id_;
00224 stream << params_.count();
00225 for (size_t index(0); index < params_.count(); ++index)
00226 {
00227 params_[index]->write(stream);
00228 }
00229 }
00230
00231 void Config::read(QDataStream& stream)
00232 {
00233 quint64 count;
00234 QString id;
00235 stream >> id;
00236 setId(id);
00237 stream >> count;
00238 clearParams();
00239 for (size_t index(0); index < count; ++index)
00240 {
00241 params_[index]->read(stream);
00242 }
00243 }
00244
00245 Config& Config::operator=(const Config& config)
00246 {
00247 setId(config.id_);
00248 clearParams();
00249 for (size_t index(0); index < config.params_.count(); index++)
00250 {
00251 addParam(config.params_[index]->clone());
00252 }
00253 return *this;
00254 }
00255
00256 QString Config::validate() const
00257 {
00258 if (id_.isEmpty())
00259 {
00260 return "The config name must not be empty.";
00261 }
00262 if (id_.contains(' '))
00263 {
00264 return "The config name must not contain <space>.";
00265 }
00266 if (params_.isEmpty())
00267 {
00268 return "Enter the config parameters.";
00269 }
00270 QString validation;
00271 for (size_t i(0); i < params_.count(); i++)
00272 {
00273 validation = params_[i]->validate();
00274 if (!validation.isEmpty())
00275 {
00276 break;
00277 }
00278 }
00279 return validation;
00280 }
00281
00282 void Config::saveAsYaml(const QString &url) const
00283 {
00284 QFile file(url + ".yaml");
00285 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
00286 {
00287 ROS_ERROR_STREAM("Unable to open the " << url.toStdString() << ".yaml file.");
00288 return;
00289 }
00290 file.write(toYaml().toStdString().c_str());
00291 file.close();
00292 ROS_INFO_STREAM("Created the " << url.toStdString() << ".yaml file.");
00293 }
00294
00295 QString Config::toYaml() const
00296 {
00297 QString yaml;
00298 for (size_t i(0); i < params_.count(); i++)
00299 {
00300 yaml += params_[i]->toYaml() + "\n";
00301 }
00302 return yaml;
00303 }
00304
00305 void Config::hideArrays()
00306 {
00307 for (size_t index(0); index < params_.count(); index++)
00308 {
00309 if (params_[index]->isArray())
00310 {
00311 throw utilities::Exception("ParamArrays must have a Params parent.");
00312 }
00313 else if (params_[index]->isParams())
00314 {
00315 findArrays(static_cast<Params*>(params_[index]));
00316 }
00317 }
00318 }
00319
00320 void Config::paramDestroyed()
00321 {
00322 ParamInterface* param = static_cast<ParamInterface*>(sender());
00323 int index(params_.indexOf(param));
00324 if (index != -1)
00325 {
00326 QString full_name(param->getFullName());
00327 params_.remove(index);
00328 emit removed(full_name);
00329 emit changed();
00330 }
00331 }
00332
00333 void Config::findArrays(Params* parent)
00334 {
00335 for (size_t index(0); index < parent->count(); index++)
00336 {
00337 if (parent->getChild(index)->isArray())
00338 {
00339 ParamInterface* size = parent->getParam("size");
00340 if (!size || !size->isParam())
00341 {
00342 throw utilities::Exception("The ParamsArray's parent must have a Param named size.");
00343 }
00344 ParamsArray* array = static_cast<ParamsArray*>(parent->getChild(index));
00345 parent->removeParam(array->getName());
00346 connect(size, SIGNAL(valueChanged(const QString&, const QVariant&)), this,
00347 SLOT(arraySizeChanged(const QString&, const QVariant&)));
00348 arrays_.insert(static_cast<Param*>(size), array);
00349 }
00350 else if (parent->getChild(index)->isParams())
00351 {
00352 findArrays(static_cast<Params*>(parent->getChild(index)));
00353 }
00354 }
00355 }
00356
00357 void Config::clearArrays()
00358 {
00359 for (iterator it(arrays_.begin()); it != arrays_.end(); it++)
00360 {
00361 arrays_[it.key()] = NULL;
00362 arrays_.remove(it.key());
00363 }
00364 arrays_.clear();
00365 }
00366
00367 void Config::arraySizeChanged(const QString& full_name, const QVariant& value)
00368 {
00369 Param* size = static_cast<Param*>(sender());
00370 ParamsArray* array = arrays_[size];
00371 array->createParams(value.toInt());
00372 findArrays(array->getParentParam());
00373 }
00374 }
00375 }