1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-19 04:52:12 +01:00

Merge pull request #27 from m-thread/m-thread/LP-16_Vehicle_Templates_Enhancements

LP-16 Vehicle templates enhancements
This commit is contained in:
a*morale 2015-07-19 13:04:52 +02:00
commit f15c3baab1
51 changed files with 280 additions and 73 deletions

View File

@ -47,7 +47,7 @@ AirframeInitialTuningPage::~AirframeInitialTuningPage()
void AirframeInitialTuningPage::initializePage()
{
ui->selectorWidget->setTemplateInfo(getWizard()->getVehicleType(), getWizard()->getVehicleSubType());
ui->selectorWidget->setTemplateInfo(getWizard()->getVehicleType(), getWizard()->getVehicleSubType(), false);
}
bool AirframeInitialTuningPage::validatePage()

View File

@ -64,7 +64,7 @@ VehicleTemplateExportDialog::VehicleTemplateExportDialog(QWidget *parent) :
m_uavoManager = pm->getObject<UAVObjectManager>();
ui->Photo->setScene(new QGraphicsScene(this));
ui->Type->setText(setupVehicleType());
ui->selectionWidget->setTemplateInfo(m_type, m_subType);
ui->selectionWidget->setTemplateInfo(m_type, m_subType, true);
connect(ui->Name, SIGNAL(textChanged(QString)), this, SLOT(updateStatus()));
connect(ui->Owner, SIGNAL(textChanged(QString)), this, SLOT(updateStatus()));
@ -229,7 +229,7 @@ void VehicleTemplateExportDialog::saveTemplate(QString path)
QJsonDocument saveDoc(exportObject);
const char *fileType = ".optmpl";
const char *fileType = ".vtmpl";
QString fileName = QString("%1-%2-%3%4")
.arg(fixFilenameString(ui->Name->text(), 20))
@ -240,7 +240,7 @@ void VehicleTemplateExportDialog::saveTemplate(QString path)
QString fullPath;
if (path.isEmpty()) {
fullPath = QString("%1%2%3").arg(QDir::homePath()).arg(QDir::separator()).arg(fileName);
fullPath = QFileDialog::getSaveFileName(this, tr("Export settings"), fullPath, QString("%1 (*%2)").arg(tr("OPTemplates"), fileType));
fullPath = QFileDialog::getSaveFileName(this, tr("Export settings"), fullPath, QString("%1 (*%2)").arg(tr("VehicleTemplates"), fileType));
} else {
fullPath = QString("%1%2%3").arg(path).arg(QDir::separator()).arg(fileName);
}
@ -272,7 +272,7 @@ QString VehicleTemplateExportDialog::fixFilenameString(QString input, int trunca
void VehicleTemplateExportDialog::exportTemplate()
{
QString path = QString("%1%2%3%4").arg(Utils::InsertStoragePath("%%STOREPATH%%cloudconfig"))
QString path = QString("%1%2%3%4").arg(Utils::InsertStoragePath("%%STOREPATH%%vehicletemplates"))
.arg(QDir::separator()).arg(getTypeDirectory()).arg(QDir::separator());
QDir dir;

View File

@ -19,17 +19,11 @@
<height>700</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>610</width>
<height>700</height>
</size>
</property>
<property name="windowTitle">
<string>Vehicle Templates</string>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="modal">
<bool>true</bool>

View File

@ -31,6 +31,8 @@
#include <QJsonArray>
#include <QDir>
#include <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include "vehicletemplateexportdialog.h"
#include "utils/pathutils.h"
@ -41,12 +43,14 @@ VehicleTemplateSelectorWidget::VehicleTemplateSelectorWidget(QWidget *parent) :
ui->setupUi(this);
ui->templateImage->setScene(new QGraphicsScene());
connect(ui->templateList, SIGNAL(itemSelectionChanged()), this, SLOT(templateSelectionChanged()));
connect(ui->deleteTemplateButton, SIGNAL(clicked()), this, SLOT(deleteSelectedTemplate()));
connect(ui->addTemplateButton, SIGNAL(clicked()), this, SLOT(addTemplate()));
}
VehicleTemplateSelectorWidget::~VehicleTemplateSelectorWidget()
{
ui->templateList->clear();
foreach(QJsonObject * templ, m_templates.values()) {
foreach(VehicleTemplate * templ, m_templates.values()) {
delete templ;
}
m_templates.clear();
@ -54,8 +58,9 @@ VehicleTemplateSelectorWidget::~VehicleTemplateSelectorWidget()
delete ui;
}
void VehicleTemplateSelectorWidget::setTemplateInfo(int vehicleType, int vehicleSubType)
void VehicleTemplateSelectorWidget::setTemplateInfo(int vehicleType, int vehicleSubType, bool showTemplateControls)
{
ui->buttonFrame->setVisible(showTemplateControls);
m_vehicleType = vehicleType;
m_vehicleSubType = vehicleSubType;
updateTemplates();
@ -69,12 +74,84 @@ QJsonObject *VehicleTemplateSelectorWidget::selectedTemplate() const
return NULL;
}
bool VehicleTemplateSelectorWidget::selectedTemplateEditable() const
{
if (ui->templateList->currentRow() >= 0) {
return ui->templateList->item(ui->templateList->currentRow())->data(Qt::UserRole + 2).value<bool>();
}
return false;
}
QString VehicleTemplateSelectorWidget::selectedTemplatePath() const
{
if (ui->templateList->currentRow() >= 0) {
return ui->templateList->item(ui->templateList->currentRow())->data(Qt::UserRole + 3).value<QString>();
}
return "";
}
void VehicleTemplateSelectorWidget::updateTemplates()
{
loadValidFiles();
setupTemplateList();
}
void VehicleTemplateSelectorWidget::deleteSelectedTemplate()
{
if (selectedTemplateEditable()) {
if (QMessageBox::question(this, tr("Delete Vehicle Template"),
"Are you sure you want to delete the selected template?",
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
QFile fileToDelete(selectedTemplatePath());
if (fileToDelete.remove()) {
QJsonObject *templObj = selectedTemplate();
if (templObj) {
VehicleTemplate *templ = m_templates[templObj->value("uuid").toString()];
m_templates.remove(templObj->value("uuid").toString());
delete templ;
}
delete ui->templateList->item(ui->templateList->currentRow());
}
}
}
}
void VehicleTemplateSelectorWidget::addTemplate()
{
QString path = QFileDialog::getOpenFileName(this, tr("Add settings"), QDir::homePath(),
tr("Vehicle Template Files (*.vtmpl *.optmpl)"));
if (path != NULL) {
QFile file(path);
if (file.open(QFile::ReadOnly)) {
QByteArray jsonData = file.readAll();
QJsonParseError error;
QJsonDocument templateDoc = QJsonDocument::fromJson(jsonData, &error);
if (error.error == QJsonParseError::NoError) {
QJsonObject json = templateDoc.object();
if (airframeIsCompatible(json["type"].toInt(), json["subtype"].toInt())) {
QFileInfo fInfo(file);
QString destinationFilePath = QString("%1/%2").arg(Utils::InsertStoragePath("%%STOREPATH%%vehicletemplates"))
.arg(getTemplatePath());
QDir dir;
if (dir.mkpath(destinationFilePath) && file.copy(QString("%1/%2").arg(destinationFilePath).arg(fInfo.fileName()))) {
updateTemplates();
} else {
QMessageBox::critical(this, tr("Error"), tr("The selected template file could not be added."));
}
} else {
QMessageBox::critical(this, tr("Error"), tr("The selected template file is not compatible with the current vehicle type."));
}
} else {
QMessageBox::critical(this, tr("Error"), tr("The selected template file is corrupt or of an unknown version."));
}
} else {
QMessageBox::critical(this, tr("Error"), tr("The selected template file could not be opened."));
}
}
}
void VehicleTemplateSelectorWidget::updatePhoto(QJsonObject *templ)
{
QPixmap photo;
@ -115,7 +192,7 @@ void VehicleTemplateSelectorWidget::updateDescription(QJsonObject *templ)
ui->templateDescription->setText(description);
} else {
ui->templateDescription->setText(tr("This option will use the current tuning settings saved on the controller, if your controller "
"is currently unconfigured, then the OpenPilot firmware defaults will be used.\n\n"
"is currently unconfigured, then the pre-configured firmware defaults will be used.\n\n"
"It is suggested that if this is a first time configuration of your controller, rather than "
"use this option, instead select a tuning set that matches your own airframe as close as "
"possible from the list above or if you are not able to fine one, then select the generic item "
@ -129,6 +206,7 @@ void VehicleTemplateSelectorWidget::templateSelectionChanged()
QJsonObject *templ = selectedTemplate();
updatePhoto(templ);
updateDescription(templ);
ui->deleteTemplateButton->setEnabled(selectedTemplateEditable());
}
}
@ -161,18 +239,20 @@ QString VehicleTemplateSelectorWidget::getTemplatePath()
}
}
void VehicleTemplateSelectorWidget::loadFilesInDir(QString templateBasePath)
void VehicleTemplateSelectorWidget::loadFilesInDir(QString templateBasePath, bool local)
{
QDir templateDir(templateBasePath);
qDebug() << "Loading templates from base path:" << templateBasePath;
QStringList names;
names << "*.optmpl";
names << "*.vtmpl"; // Vehicle template
templateDir.setNameFilters(names);
templateDir.setSorting(QDir::Name);
QStringList files = templateDir.entryList();
foreach(QString fileName, files) {
QFile file(QString("%1/%2").arg(templateDir.absolutePath()).arg(fileName));
QString fullPathName = QString("%1/%2").arg(templateDir.absolutePath()).arg(fileName);
QFile file(fullPathName);
if (file.open(QFile::ReadOnly)) {
QByteArray jsonData = file.readAll();
@ -183,7 +263,7 @@ void VehicleTemplateSelectorWidget::loadFilesInDir(QString templateBasePath)
if (airframeIsCompatible(json["type"].toInt(), json["subtype"].toInt())) {
QString uuid = json["uuid"].toString();
if (!m_templates.contains(uuid)) {
m_templates[json["uuid"].toString()] = new QJsonObject(json);
m_templates[json["uuid"].toString()] = new VehicleTemplate(new QJsonObject(json), local, fullPathName);
}
}
} else {
@ -198,13 +278,13 @@ void VehicleTemplateSelectorWidget::loadFilesInDir(QString templateBasePath)
void VehicleTemplateSelectorWidget::loadValidFiles()
{
ui->templateList->clear();
foreach(QJsonObject * templ, m_templates.values()) {
foreach(VehicleTemplate * templ, m_templates.values()) {
delete templ;
}
m_templates.clear();
QString path = getTemplatePath();
loadFilesInDir(QString("%1/%2/").arg(Utils::InsertDataPath("%%DATAPATH%%cloudconfig")).arg(path));
loadFilesInDir(QString("%1/%2/").arg(Utils::InsertStoragePath("%%STOREPATH%%cloudconfig")).arg(path));
loadFilesInDir(QString("%1/%2/").arg(Utils::InsertDataPath("%%DATAPATH%%vehicletemplates")).arg(path), false);
loadFilesInDir(QString("%1/%2/").arg(Utils::InsertStoragePath("%%STOREPATH%%vehicletemplates")).arg(path), true);
}
void VehicleTemplateSelectorWidget::setupTemplateList()
@ -212,10 +292,18 @@ void VehicleTemplateSelectorWidget::setupTemplateList()
QListWidgetItem *item;
foreach(QString templ, m_templates.keys()) {
QJsonObject *json = m_templates[templ];
VehicleTemplate *vtemplate = m_templates[templ];
item = new QListWidgetItem(json->value("name").toString(), ui->templateList);
item->setData(Qt::UserRole + 1, QVariant::fromValue(json));
item = new QListWidgetItem(vtemplate->templateObject()->value("name").toString(), ui->templateList);
item->setData(Qt::UserRole + 1, QVariant::fromValue(vtemplate->templateObject()));
item->setData(Qt::UserRole + 2, QVariant::fromValue(vtemplate->editable()));
if (vtemplate->editable()) {
item->setData(Qt::ForegroundRole, QVariant::fromValue(QColor(Qt::darkGreen)));
item->setData(Qt::ToolTipRole, QVariant::fromValue(tr("Local template.")));
} else {
item->setData(Qt::ToolTipRole, QVariant::fromValue(tr("Built-in template.")));
}
item->setData(Qt::UserRole + 3, QVariant::fromValue(vtemplate->templatePath()));
}
ui->templateList->sortItems(Qt::AscendingOrder);

View File

@ -36,15 +36,47 @@ namespace Ui {
class VehicleTemplateSelectorWidget;
}
class VehicleTemplate {
public:
VehicleTemplate(QJsonObject *templateObject, bool editable, QString templatePath) :
m_templateObject(templateObject), m_editable(editable), m_templatePath(templatePath) {}
~VehicleTemplate()
{
if (m_templateObject) {
delete m_templateObject;
}
}
QJsonObject *templateObject()
{
return m_templateObject;
}
bool editable()
{
return m_editable;
}
QString templatePath()
{
return m_templatePath;
}
private:
QJsonObject *m_templateObject;
bool m_editable;
QString m_templatePath;
};
class VehicleTemplateSelectorWidget : public QWidget {
Q_OBJECT
public:
explicit VehicleTemplateSelectorWidget(QWidget *parent = 0);
~VehicleTemplateSelectorWidget();
void setTemplateInfo(int vehicleType, int vehicleSubType);
void setTemplateInfo(int vehicleType, int vehicleSubType, bool showTemplateControls);
QJsonObject *selectedTemplate() const;
public slots:
void templateSelectionChanged();
@ -57,20 +89,24 @@ private:
int m_vehicleType;
int m_vehicleSubType;
QMap<QString, QJsonObject *> m_templates;
QMap<QString, VehicleTemplate *> m_templates;
QGraphicsPixmapItem *m_photoItem;
void loadValidFiles();
void loadFilesInDir(QString templateBasePath);
void loadFilesInDir(QString templateBasePath, bool local);
void setupTemplateList();
QString getTemplateKey(QJsonObject *templ);
void updatePhoto(QJsonObject *templ);
void updateDescription(QJsonObject *templ);
bool airframeIsCompatible(int vehicleType, int vehicleSubType);
QString getTemplatePath();
bool selectedTemplateEditable() const;
QString selectedTemplatePath() const;
private slots:
void updateTemplates();
void deleteSelectedTemplate();
void addTemplate();
};
Q_DECLARE_METATYPE(QJsonObject *)

View File

@ -13,71 +13,160 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="2,0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,4">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="templateList">
<property name="minimumSize">
<size>
<width>0</width>
<height>300</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QGraphicsView" name="templateImage">
<property name="minimumSize">
<size>
<width>250</width>
<height>250</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgba(254, 254, 254, 0);</string>
</property>
<property name="interactive">
<bool>false</bool>
</property>
<property name="renderHints">
<set>QPainter::Antialiasing|QPainter::HighQualityAntialiasing|QPainter::TextAntialiasing</set>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QFrame" name="buttonFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="addTemplateButton">
<property name="text">
<string>Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteTemplateButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QTextEdit" name="templateDescription">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<widget class="QGraphicsView" name="templateImage">
<property name="minimumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
<property name="styleSheet">
<string notr="true">background-color: rgba(254, 254, 254, 0);</string>
</property>
<property name="undoRedoEnabled">
<property name="interactive">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
<property name="renderHints">
<set>QPainter::Antialiasing|QPainter::HighQualityAntialiasing|QPainter::SmoothPixmapTransform|QPainter::TextAntialiasing</set>
</property>
<property name="placeholderText">
<string>Information about the Vehicle in short.</string>
<property name="resizeAnchor">
<enum>QGraphicsView::AnchorViewCenter</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QTextEdit" name="templateDescription">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Information about the Vehicle in short.</string>
</property>
</widget>
</widget>
</item>
</layout>
</widget>

View File

@ -1 +0,0 @@
This folder is here to host downloaded or bundled vehicle settings template files (.optmpl).

View File

@ -2,7 +2,7 @@ include(../../openpilotgcs.pri)
TEMPLATE = aux
DATACOLLECTIONS = cloudconfig configurations dials models pfd sounds diagrams mapicons stylesheets
DATACOLLECTIONS = vehicletemplates configurations dials models pfd sounds diagrams mapicons stylesheets
equals(copydata, 1) {
for(dir, DATACOLLECTIONS) {

View File

@ -1 +1 @@
This folder is here to host downloaded or bundled vehicle settings template files (.optmpl).
This folder is here to host downloaded or bundled vehicle settings template files (*.vtmpl, *.optmpl).

View File

@ -1 +1 @@
This folder is here to host downloaded or bundled vehicle settings template files (.optmpl).
This folder is here to host downloaded or bundled vehicle settings template files (*.vtmpl, *.optmpl).

View File

@ -1 +1 @@
This folder is here to host downloaded or bundled vehicle settings template files (.optmpl).
This folder is here to host downloaded or bundled vehicle settings template files (*.vtmpl, *.optmpl).

View File

@ -1 +1 @@
This folder is here to host downloaded or bundled vehicle settings template files (.optmpl).
This folder is here to host downloaded or bundled vehicle settings template files (*.vtmpl, *.optmpl).

View File

@ -0,0 +1 @@
This folder is here to host downloaded or bundled vehicle settings template files (*.vtmpl, *.optmpl).