2 ******************************************************************************
4 * @file vehicletemplateselectorwidget.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
8 * @addtogroup VehicleTemplateSelectorWidget
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
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 "vehicletemplateselectorwidget.h"
29 #include "ui_vehicletemplateselectorwidget.h"
30 #include <QJsonDocument>
34 #include <QMessageBox>
35 #include <QFileDialog>
36 #include "vehicletemplateexportdialog.h"
37 #include "utils/pathutils.h"
39 VehicleTemplateSelectorWidget::VehicleTemplateSelectorWidget(QWidget
*parent
) :
41 ui(new Ui::VehicleTemplateSelectorWidget
), m_photoItem(NULL
)
44 ui
->templateImage
->setScene(new QGraphicsScene());
45 connect(ui
->templateList
, SIGNAL(itemSelectionChanged()), this, SLOT(templateSelectionChanged()));
46 connect(ui
->deleteTemplateButton
, SIGNAL(clicked()), this, SLOT(deleteSelectedTemplate()));
47 connect(ui
->addTemplateButton
, SIGNAL(clicked()), this, SLOT(addTemplate()));
50 VehicleTemplateSelectorWidget::~VehicleTemplateSelectorWidget()
52 ui
->templateList
->clear();
53 foreach(VehicleTemplate
* templ
, m_templates
.values()) {
61 void VehicleTemplateSelectorWidget::setTemplateInfo(int vehicleType
, int vehicleSubType
, bool showTemplateControls
)
63 ui
->buttonFrame
->setVisible(showTemplateControls
);
64 m_vehicleType
= vehicleType
;
65 m_vehicleSubType
= vehicleSubType
;
69 QJsonObject
*VehicleTemplateSelectorWidget::selectedTemplate() const
71 if (ui
->templateList
->currentRow() >= 0) {
72 return ui
->templateList
->item(ui
->templateList
->currentRow())->data(Qt::UserRole
+ 1).value
<QJsonObject
*>();
77 bool VehicleTemplateSelectorWidget::selectedTemplateEditable() const
79 if (ui
->templateList
->currentRow() >= 0) {
80 return ui
->templateList
->item(ui
->templateList
->currentRow())->data(Qt::UserRole
+ 2).value
<bool>();
85 QString
VehicleTemplateSelectorWidget::selectedTemplatePath() const
87 if (ui
->templateList
->currentRow() >= 0) {
88 return ui
->templateList
->item(ui
->templateList
->currentRow())->data(Qt::UserRole
+ 3).value
<QString
>();
93 void VehicleTemplateSelectorWidget::updateTemplates()
99 void VehicleTemplateSelectorWidget::deleteSelectedTemplate()
101 if (selectedTemplateEditable()) {
102 if (QMessageBox::question(this, tr("Delete Vehicle Template"),
103 "Are you sure you want to delete the selected template?",
104 QMessageBox::Yes
| QMessageBox::No
) == QMessageBox::Yes
) {
105 QFile
fileToDelete(selectedTemplatePath());
106 if (fileToDelete
.remove()) {
107 QJsonObject
*templObj
= selectedTemplate();
109 VehicleTemplate
*templ
= m_templates
[templObj
->value("uuid").toString()];
110 m_templates
.remove(templObj
->value("uuid").toString());
113 delete ui
->templateList
->item(ui
->templateList
->currentRow());
119 void VehicleTemplateSelectorWidget::addTemplate()
121 QString path
= QFileDialog::getOpenFileName(this, tr("Add settings"), QDir::homePath(),
122 tr("Vehicle Template Files (*.vtmpl *.optmpl)"));
127 if (file
.open(QFile::ReadOnly
)) {
128 QByteArray jsonData
= file
.readAll();
129 QJsonParseError error
;
130 QJsonDocument templateDoc
= QJsonDocument::fromJson(jsonData
, &error
);
131 if (error
.error
== QJsonParseError::NoError
) {
132 QJsonObject json
= templateDoc
.object();
133 if (airframeIsCompatible(json
["type"].toInt(), json
["subtype"].toInt())) {
134 QFileInfo
fInfo(file
);
135 QString destinationFilePath
= QString("%1/%2").arg(Utils::InsertStoragePath("%%STOREPATH%%vehicletemplates"))
136 .arg(getTemplatePath());
138 if (dir
.mkpath(destinationFilePath
) && file
.copy(QString("%1/%2").arg(destinationFilePath
).arg(fInfo
.fileName()))) {
141 QMessageBox::critical(this, tr("Error"), tr("The selected template file could not be added."));
144 QMessageBox::critical(this, tr("Error"), tr("The selected template file is not compatible with the current vehicle type."));
147 QMessageBox::critical(this, tr("Error"), tr("The selected template file is corrupt or of an unknown version."));
150 QMessageBox::critical(this, tr("Error"), tr("The selected template file could not be opened."));
155 void VehicleTemplateSelectorWidget::updatePhoto(QJsonObject
*templ
)
159 if (m_photoItem
!= NULL
) {
160 ui
->templateImage
->scene()->removeItem(m_photoItem
);
162 if (templ
!= NULL
&& !templ
->value("photo").isUndefined()) {
163 QByteArray imageData
= QByteArray::fromBase64(templ
->value("photo").toString().toLatin1());
164 photo
.loadFromData(imageData
, "PNG");
166 photo
.load(":/core/images/librepilot_logo_500.png");
168 m_photoItem
= ui
->templateImage
->scene()->addPixmap(photo
);
169 ui
->templateImage
->setSceneRect(ui
->templateImage
->scene()->itemsBoundingRect());
170 ui
->templateImage
->fitInView(ui
->templateImage
->scene()->itemsBoundingRect(), Qt::KeepAspectRatio
);
173 void VehicleTemplateSelectorWidget::updateDescription(QJsonObject
*templ
)
177 description
.append("<b>").append(tr("Name of Vehicle: ")).append("</b>").append(templ
->value("name").toString()).append("<br>");
178 description
.append("<b>").append(tr("Name of Owner: ")).append("</b>").append(templ
->value("owner").toString());
179 if (templ
->value("nick") != QStringLiteral("")) {
180 description
.append(" (").append(templ
->value("nick").toString()).append(")");
182 description
.append("<br>");
183 description
.append("<b>").append(tr("Size: ")).append("</b>").append(templ
->value("size").toString()).append("<br>");
184 description
.append("<b>").append(tr("Weight: ")).append("</b>").append(templ
->value("weight").toString()).append("<br>");
185 description
.append("<b>").append(tr("Motor(s): ")).append("</b>").append(templ
->value("motor").toString()).append("<br>");
186 description
.append("<b>").append(tr("ESC(s): ")).append("</b>").append(templ
->value("esc").toString()).append("<br>");
187 description
.append("<b>").append(tr("Servo(s): ")).append("</b>").append(templ
->value("servo").toString()).append("<br>");
188 description
.append("<b>").append(tr("Battery: ")).append("</b>").append(templ
->value("battery").toString()).append("<br>");
189 description
.append("<b>").append(tr("Propellers(s): ")).append("</b>").append(templ
->value("propeller").toString()).append("<br>");
190 description
.append("<b>").append(tr("Controller: ")).append("</b>").append(templ
->value("controller").toString()).append("<br>");
191 description
.append("<b>").append(tr("Comments: ")).append("</b>").append(templ
->value("comment").toString());
192 ui
->templateDescription
->setText(description
);
194 ui
->templateDescription
->setText(tr("This option will use the current tuning settings saved on the controller, if your controller "
195 "is currently unconfigured, then the pre-configured firmware defaults will be used.\n\n"
196 "It is suggested that if this is a first time configuration of your controller, rather than "
197 "use this option, instead select a tuning set that matches your own airframe as close as "
198 "possible from the list above or if you are not able to fine one, then select the generic item "
203 void VehicleTemplateSelectorWidget::templateSelectionChanged()
205 if (ui
->templateList
->currentRow() >= 0) {
206 QJsonObject
*templ
= selectedTemplate();
208 updateDescription(templ
);
209 ui
->deleteTemplateButton
->setEnabled(selectedTemplateEditable());
213 bool VehicleTemplateSelectorWidget::airframeIsCompatible(int vehicleType
, int vehicleSubType
)
215 if (vehicleType
!= m_vehicleType
) {
219 return vehicleSubType
== m_vehicleSubType
;
222 QString
VehicleTemplateSelectorWidget::getTemplatePath()
224 switch (m_vehicleType
) {
225 case VehicleConfigurationSource::VEHICLE_FIXEDWING
:
226 return VehicleTemplateExportDialog::EXPORT_FIXEDWING_NAME
;
228 case VehicleConfigurationSource::VEHICLE_MULTI
:
229 return VehicleTemplateExportDialog::EXPORT_MULTI_NAME
;
231 case VehicleConfigurationSource::VEHICLE_HELI
:
232 return VehicleTemplateExportDialog::EXPORT_HELI_NAME
;
234 case VehicleConfigurationSource::VEHICLE_SURFACE
:
235 return VehicleTemplateExportDialog::EXPORT_SURFACE_NAME
;
242 void VehicleTemplateSelectorWidget::loadFilesInDir(QString templateBasePath
, bool local
)
244 QDir
templateDir(templateBasePath
);
246 qDebug() << "Loading templates from base path:" << templateBasePath
;
249 names
<< "*.vtmpl"; // Vehicle template
250 templateDir
.setNameFilters(names
);
251 templateDir
.setSorting(QDir::Name
);
252 QStringList files
= templateDir
.entryList();
253 foreach(QString fileName
, files
) {
254 QString fullPathName
= QString("%1/%2").arg(templateDir
.absolutePath()).arg(fileName
);
255 QFile
file(fullPathName
);
257 if (file
.open(QFile::ReadOnly
)) {
258 QByteArray jsonData
= file
.readAll();
259 QJsonParseError error
;
260 QJsonDocument templateDoc
= QJsonDocument::fromJson(jsonData
, &error
);
261 if (error
.error
== QJsonParseError::NoError
) {
262 QJsonObject json
= templateDoc
.object();
263 if (airframeIsCompatible(json
["type"].toInt(), json
["subtype"].toInt())) {
264 QString uuid
= json
["uuid"].toString();
265 if (!m_templates
.contains(uuid
)) {
266 m_templates
[json
["uuid"].toString()] = new VehicleTemplate(new QJsonObject(json
), local
, fullPathName
);
270 qDebug() << "Error parsing json file: "
271 << fileName
<< ". Error was:" << error
.errorString();
278 void VehicleTemplateSelectorWidget::loadValidFiles()
280 ui
->templateList
->clear();
281 foreach(VehicleTemplate
* templ
, m_templates
.values()) {
285 QString path
= getTemplatePath();
286 loadFilesInDir(QString("%1/%2/").arg(Utils::InsertDataPath("%%DATAPATH%%vehicletemplates")).arg(path
), false);
287 loadFilesInDir(QString("%1/%2/").arg(Utils::InsertStoragePath("%%STOREPATH%%vehicletemplates")).arg(path
), true);
290 void VehicleTemplateSelectorWidget::setupTemplateList()
292 QListWidgetItem
*item
;
294 foreach(QString templ
, m_templates
.keys()) {
295 VehicleTemplate
*vtemplate
= m_templates
[templ
];
297 item
= new QListWidgetItem(vtemplate
->templateObject()->value("name").toString(), ui
->templateList
);
298 item
->setData(Qt::UserRole
+ 1, QVariant::fromValue(vtemplate
->templateObject()));
299 item
->setData(Qt::UserRole
+ 2, QVariant::fromValue(vtemplate
->editable()));
300 if (vtemplate
->editable()) {
301 item
->setData(Qt::ForegroundRole
, QVariant::fromValue(QColor(Qt::darkGreen
)));
302 item
->setData(Qt::ToolTipRole
, QVariant::fromValue(tr("Local template.")));
304 item
->setData(Qt::ToolTipRole
, QVariant::fromValue(tr("Built-in template.")));
306 item
->setData(Qt::UserRole
+ 3, QVariant::fromValue(vtemplate
->templatePath()));
308 ui
->templateList
->sortItems(Qt::AscendingOrder
);
310 item
= new QListWidgetItem(tr("Current Tuning"));
311 item
->setData(Qt::UserRole
+ 1, QVariant::fromValue((QJsonObject
*)NULL
));
312 ui
->templateList
->insertItem(0, item
);
313 ui
->templateList
->setCurrentRow(0);
314 // TODO Add generics to top under item Current tuning
317 QString
VehicleTemplateSelectorWidget::getTemplateKey(QJsonObject
*templ
)
319 return QString(templ
->value("name").toString());
322 void VehicleTemplateSelectorWidget::resizeEvent(QResizeEvent
*)
324 ui
->templateImage
->setSceneRect(ui
->templateImage
->scene()->itemsBoundingRect());
325 ui
->templateImage
->fitInView(ui
->templateImage
->scene()->itemsBoundingRect(), Qt::KeepAspectRatio
);
328 void VehicleTemplateSelectorWidget::showEvent(QShowEvent
*)
330 ui
->templateImage
->setSceneRect(ui
->templateImage
->scene()->itemsBoundingRect());
331 ui
->templateImage
->fitInView(ui
->templateImage
->scene()->itemsBoundingRect(), Qt::KeepAspectRatio
);