Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / plugins / uavsettingsimportexport / uavsettingsimportexportfactory.cpp
blobb1d803aa34a281efcd1995e8cf946f5490efc474
1 /**
2 ******************************************************************************
4 * @file uavsettingsimportexportfactory.cpp
5 * @author (C) 2011 The OpenPilot Team, http://www.openpilot.org
6 * @addtogroup GCSPlugins GCS Plugins
7 * @{
8 * @addtogroup UAVSettingsImportExport UAVSettings Import/Export Plugin
9 * @{
10 * @brief UAVSettings Import/Export Plugin
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "uavsettingsimportexportfactory.h"
29 #include <QtPlugin>
30 #include <QStringList>
31 #include <QDebug>
32 #include <QCheckBox>
33 #include "importsummary.h"
34 #include "version_info/version_info.h"
36 // for menu item
37 #include <coreplugin/coreconstants.h>
38 #include <coreplugin/actionmanager/actionmanager.h>
39 #include <coreplugin/icore.h>
40 #include <QKeySequence>
42 // for UAVObjects
43 #include "uavdataobject.h"
44 #include "uavobjectmanager.h"
45 #include "extensionsystem/pluginmanager.h"
47 // for XML object
48 #include <QDomDocument>
50 // for file dialog and error messages
51 #include <QFileDialog>
52 #include <QMessageBox>
54 UAVSettingsImportExportFactory::~UAVSettingsImportExportFactory()
56 // Do nothing
59 UAVSettingsImportExportFactory::UAVSettingsImportExportFactory(QObject *parent) : QObject(parent)
61 // Add Menu entry
62 Core::ActionManager *am = Core::ICore::instance()->actionManager();
63 Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_FILE);
64 Core::Command *cmd = am->registerAction(new QAction(this),
65 "UAVSettingsImportExportPlugin.UAVSettingsExport",
66 QList<int>() <<
67 Core::Constants::C_GLOBAL_ID);
69 cmd->setDefaultKeySequence(QKeySequence("Ctrl+E"));
70 cmd->action()->setText(tr("Export UAV Settings..."));
71 ac->addAction(cmd, Core::Constants::G_FILE_SAVE);
72 connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(exportUAVSettings()));
74 cmd = am->registerAction(new QAction(this),
75 "UAVSettingsImportExportPlugin.UAVSettingsImport",
76 QList<int>() <<
77 Core::Constants::C_GLOBAL_ID);
78 cmd->setDefaultKeySequence(QKeySequence("Ctrl+I"));
79 cmd->action()->setText(tr("Import UAV Settings..."));
80 ac->addAction(cmd, Core::Constants::G_FILE_SAVE);
81 connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(importUAVSettings()));
83 ac = am->actionContainer(Core::Constants::M_HELP);
84 cmd = am->registerAction(new QAction(this),
85 "UAVSettingsImportExportPlugin.UAVDataExport",
86 QList<int>() <<
87 Core::Constants::C_GLOBAL_ID);
88 cmd->action()->setText(tr("Export UAV Data..."));
89 ac->addAction(cmd, Core::Constants::G_HELP_HELP);
90 connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(exportUAVData()));
93 // Slot called by the menu manager on user action
94 void UAVSettingsImportExportFactory::importUAVSettings()
96 // ask for file name
97 QString fileName;
98 QString filters = tr("UAVObjects XML files (*.uav);; XML files (*.xml)");
100 fileName = QFileDialog::getOpenFileName(0, tr("Import UAV Settings"), "", filters);
101 if (fileName.isEmpty()) {
102 return;
105 // Now open the file
106 QFile file(fileName);
107 QDomDocument doc("UAVObjects");
108 file.open(QFile::ReadOnly | QFile::Text);
109 if (!doc.setContent(file.readAll())) {
110 QMessageBox msgBox;
111 msgBox.setText(tr("File Parsing Failed."));
112 msgBox.setInformativeText(tr("This file is not a correct XML file"));
113 msgBox.setStandardButtons(QMessageBox::Ok);
114 msgBox.exec();
115 return;
117 file.close();
119 // find the root of settings subtree
120 emit importAboutToBegin();
121 qDebug() << "Import about to begin";
123 QDomElement root = doc.documentElement();
124 if (root.tagName() == "uavobjects") {
125 root = root.firstChildElement("settings");
127 if (root.isNull() || (root.tagName() != "settings")) {
128 QMessageBox msgBox;
129 msgBox.setText(tr("Wrong file contents"));
130 msgBox.setInformativeText(tr("This file does not contain correct UAVSettings"));
131 msgBox.setStandardButtons(QMessageBox::Ok);
132 msgBox.exec();
133 return;
136 // We are now ok: setup the import summary dialog & update it as we
137 // go along.
138 ImportSummaryDialog swui((QWidget *)Core::ICore::instance()->mainWindow());
140 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
141 UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
142 swui.show();
144 QDomNode node = root.firstChild();
145 while (!node.isNull()) {
146 QDomElement e = node.toElement();
147 if (e.tagName() == "object") {
148 // - Read each object
149 QString uavObjectName = e.attribute("name");
150 uint uavObjectID = e.attribute("id").toUInt(NULL, 16);
152 // Sanity Check:
153 UAVObject *obj = objManager->getObject(uavObjectName);
154 if (obj == NULL) {
155 // This object is unknown!
156 qDebug() << "Object unknown:" << uavObjectName << uavObjectID;
157 swui.addLine(uavObjectName, "Error (Object unknown)", false);
158 } else {
159 // - Update each field
160 // - Issue and "updated" command
161 bool error = false;
162 bool setError = false;
163 QDomNode field = node.firstChild();
164 while (!field.isNull()) {
165 QDomElement f = field.toElement();
166 if (f.tagName() == "field") {
167 UAVObjectField *uavfield = obj->getField(f.attribute("name"));
168 if (uavfield) {
169 QStringList list = f.attribute("values").split(",");
170 if (list.length() == 1) {
171 if (false == uavfield->checkValue(f.attribute("values"))) {
172 qDebug() << "checkValue returned false on: " << uavObjectName << f.attribute("values");
173 setError = true;
174 } else {
175 uavfield->setValue(f.attribute("values"));
177 } else {
178 // This is an enum:
179 int i = 0;
180 QStringList list = f.attribute("values").split(",");
181 foreach(QString element, list) {
182 if (false == uavfield->checkValue(element, i)) {
183 qDebug() << "checkValue(list) returned false on: " << uavObjectName << list;
184 setError = true;
185 } else {
186 uavfield->setValue(element, i);
188 i++;
191 } else {
192 error = true;
195 field = field.nextSibling();
197 obj->updated();
199 if (error) {
200 swui.addLine(uavObjectName, "Warning (Object field unknown)", true);
201 } else if (uavObjectID != obj->getObjID()) {
202 qDebug() << "Mismatch for Object " << uavObjectName << uavObjectID << " - " << obj->getObjID();
203 swui.addLine(uavObjectName, "Warning (ObjectID mismatch)", true);
204 } else if (setError) {
205 swui.addLine(uavObjectName, "Warning (Objects field value(s) invalid)", false);
206 } else {
207 swui.addLine(uavObjectName, "OK", true);
211 node = node.nextSibling();
213 qDebug() << "End import";
214 swui.exec();
217 // Create an XML document from UAVObject database
218 QString UAVSettingsImportExportFactory::createXMLDocument(const enum storedData what, const bool fullExport)
220 // generate an XML first (used for all export formats as a formatted data source)
221 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
222 UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
224 // create an XML root
225 QDomDocument doc("UAVObjects");
226 QDomElement root = doc.createElement("uavobjects");
228 doc.appendChild(root);
230 // add hardware, firmware and GCS version info
231 QDomElement versionInfo = doc.createElement("version");
232 root.appendChild(versionInfo);
234 UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
235 deviceDescriptorStruct board = utilMngr->getBoardDescriptionStruct();
237 QDomElement hw = doc.createElement("hardware");
238 hw.setAttribute("type", QString().setNum(board.boardType, 16));
239 hw.setAttribute("revision", QString().setNum(board.boardRevision, 16));
240 hw.setAttribute("serial", QString(utilMngr->getBoardCPUSerial().toHex()));
241 versionInfo.appendChild(hw);
243 QDomElement fw = doc.createElement("firmware");
244 QString uavo = board.uavoHash.toHex();
245 fw.setAttribute("tag", board.gitTag);
246 fw.setAttribute("date", board.gitDate);
247 fw.setAttribute("hash", board.gitHash);
248 fw.setAttribute("uavo", uavo.left(8));
249 versionInfo.appendChild(fw);
251 QDomElement gcs = doc.createElement("gcs");
252 gcs.setAttribute("tag", VersionInfo::tagOrBranch() + VersionInfo::dirty());
253 gcs.setAttribute("date", VersionInfo::dateTime());
254 gcs.setAttribute("hash", VersionInfo::hash().left(8));
255 gcs.setAttribute("uavo", VersionInfo::uavoHash().left(8));
256 versionInfo.appendChild(gcs);
258 // create settings and/or data elements
259 QDomElement settings = doc.createElement("settings");
260 QDomElement data = doc.createElement("data");
262 switch (what) {
263 case Settings:
264 root.appendChild(settings);
265 break;
266 case Data:
267 root.appendChild(data);
268 break;
269 case Both:
270 root.appendChild(data);
271 root.appendChild(settings);
272 break;
275 // iterate over settings objects
276 QList< QList<UAVDataObject *> > objList = objManager->getDataObjects();
277 foreach(QList<UAVDataObject *> list, objList) {
278 foreach(UAVDataObject * obj, list) {
279 if (((what == Settings) && obj->isSettingsObject()) ||
280 ((what == Data) && !obj->isSettingsObject()) ||
281 (what == Both)) {
282 // add each object to the XML
283 QDomElement o = doc.createElement("object");
284 o.setAttribute("name", obj->getName());
285 o.setAttribute("id", QString("0x") + QString().setNum(obj->getObjID(), 16).toUpper());
286 if (fullExport) {
287 QDomElement d = doc.createElement("description");
288 QDomText t = doc.createTextNode(obj->getDescription().remove("@Ref ", Qt::CaseInsensitive));
289 d.appendChild(t);
290 o.appendChild(d);
293 // iterate over fields
294 QList<UAVObjectField *> fieldList = obj->getFields();
296 foreach(UAVObjectField * field, fieldList) {
297 QDomElement f = doc.createElement("field");
299 // iterate over values
300 QString vals;
301 quint32 nelem = field->getNumElements();
303 for (unsigned int n = 0; n < nelem; ++n) {
304 vals.append(QString("%1,").arg(field->getValue(n).toString()));
306 vals.chop(1);
308 f.setAttribute("name", field->getName());
309 f.setAttribute("values", vals);
310 if (fullExport) {
311 f.setAttribute("type", field->getTypeAsString());
312 f.setAttribute("units", field->getUnits());
313 f.setAttribute("elements", nelem);
314 if (field->getType() == UAVObjectField::ENUM) {
315 f.setAttribute("options", field->getOptions().join(","));
318 o.appendChild(f);
321 // append to the settings or data element
322 if (obj->isSettingsObject()) {
323 settings.appendChild(o);
324 } else {
325 data.appendChild(o);
331 return doc.toString(4);
334 // Slot called by the menu manager on user action
335 void UAVSettingsImportExportFactory::exportUAVSettings()
337 // ask for file name
338 QString fileName;
339 QString filters = tr("UAVObjects XML files (*.uav)");
341 fileName = QFileDialog::getSaveFileName(0, tr("Save UAVSettings File As"), "", filters);
342 if (fileName.isEmpty()) {
343 return;
346 // If the filename ends with .xml, we will do a full export, otherwise, a simple export
347 bool fullExport = false;
348 if (fileName.endsWith(".xml")) {
349 fullExport = true;
350 } else if (!fileName.endsWith(".uav")) {
351 fileName.append(".uav");
354 // generate an XML first (used for all export formats as a formatted data source)
355 QString xml = createXMLDocument(Settings, fullExport);
357 // save file
358 QFile file(fileName);
359 if (file.open(QIODevice::WriteOnly) &&
360 (file.write(xml.toLatin1()) != -1)) {
361 file.close();
362 } else {
363 QMessageBox::critical(0,
364 tr("UAV Settings Export"),
365 tr("Unable to save settings: ") + fileName,
366 QMessageBox::Ok);
367 return;
370 QMessageBox msgBox;
371 msgBox.setText(tr("Settings saved."));
372 msgBox.setStandardButtons(QMessageBox::Ok);
373 msgBox.exec();
376 // Slot called by the menu manager on user action
377 void UAVSettingsImportExportFactory::exportUAVData()
379 if (QMessageBox::question(0, tr("Are you sure?"),
380 tr("This option is only useful for passing your current "
381 "system data to the technical support staff. "
382 "Do you really want to export?"),
383 QMessageBox::Ok | QMessageBox::Cancel,
384 QMessageBox::Ok) != QMessageBox::Ok) {
385 return;
388 // ask for file name
389 QString fileName;
390 QString filters = tr("UAVObjects XML files (*.uav)");
392 fileName = QFileDialog::getSaveFileName(0, tr("Save UAVData File As"), "", filters);
393 if (fileName.isEmpty()) {
394 return;
397 // If the filename ends with .xml, we will do a full export, otherwise, a simple export
398 bool fullExport = false;
399 if (fileName.endsWith(".xml")) {
400 fullExport = true;
401 } else if (!fileName.endsWith(".uav")) {
402 fileName.append(".uav");
405 // generate an XML first (used for all export formats as a formatted data source)
406 QString xml = createXMLDocument(Both, fullExport);
408 // save file
409 QFile file(fileName);
410 if (file.open(QIODevice::WriteOnly) &&
411 (file.write(xml.toLatin1()) != -1)) {
412 file.close();
413 } else {
414 QMessageBox::critical(0,
415 tr("UAV Data Export"),
416 tr("Unable to save data: ") + fileName,
417 QMessageBox::Ok);
418 return;
421 QMessageBox msgBox;
422 msgBox.setText(tr("Data saved."));
423 msgBox.setStandardButtons(QMessageBox::Ok);
424 msgBox.exec();