fix(cpn): radio specific name and label validators (#4670)
Only allows valid characters in names, drops invalid characters if present
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include "yaml_ops.h"
|
||||
#include "yaml_generalsettings.h"
|
||||
#include "yaml_modeldata.h"
|
||||
#include "labelvalidator.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
@@ -113,11 +114,14 @@ bool loadLabelsListFromYaml(RadioData::ModelLabels& labels,
|
||||
std::string lbl = it->first.as<std::string>();
|
||||
RadioData::LabelData ld;
|
||||
ld.name = QString::fromStdString(lbl);
|
||||
if (lbls[lbl]["selected"])
|
||||
ld.selected = lbls[lbl]["selected"].as<bool>();
|
||||
else
|
||||
ld.selected = false;
|
||||
labels.append(ld);
|
||||
YamlValidateLabel(ld.name);
|
||||
if (!ld.name.isEmpty()) {
|
||||
if (lbls[lbl]["selected"])
|
||||
ld.selected = lbls[lbl]["selected"].as<bool>();
|
||||
else
|
||||
ld.selected = false;
|
||||
labels.append(ld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,17 @@
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
void YamlValidateNames(GeneralSettings& gs, Board::Type board)
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_INPUTS; i++) {
|
||||
YamlValidateName(gs.inputConfig[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_SWITCHES; i++) {
|
||||
YamlValidateName(gs.switchConfig[i].name, board);
|
||||
}
|
||||
}
|
||||
|
||||
const YamlLookupTable beeperModeLut = {
|
||||
{ GeneralSettings::BEEPER_QUIET, "mode_quiet" },
|
||||
{ GeneralSettings::BEEPER_ALARMS_ONLY, "mode_alarms" },
|
||||
@@ -599,7 +610,8 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
|
||||
node["labelMultiMode"] >> rhs.labelMultiMode;
|
||||
node["favMultiMode"] >> rhs.favMultiMode;
|
||||
|
||||
// fix ups
|
||||
// perform integrity checks and fix-ups
|
||||
YamlValidateNames(rhs, fw->getBoard());
|
||||
rhs.validateFlexSwitches();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -41,6 +41,57 @@
|
||||
|
||||
SemanticVersion version; // used for data conversions
|
||||
|
||||
void YamlValidateLabelsNames(ModelData& model, Board::Type board)
|
||||
{
|
||||
YamlValidateName(model.name, board);
|
||||
|
||||
QStringList lst = QString(model.labels).split(',', Qt::SkipEmptyParts);
|
||||
|
||||
for (int i = lst.count() - 1; i >= 0; i--) {
|
||||
YamlValidateLabel(lst[i]);
|
||||
if (lst.at(i).isEmpty())
|
||||
lst.removeAt(i);
|
||||
}
|
||||
|
||||
strcpy(model.labels, QString(lst.join(',')).toLatin1().data());
|
||||
|
||||
for (int i = 0; i < CPN_MAX_CURVES; i++) {
|
||||
YamlValidateName(model.curves[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
|
||||
YamlValidateName(model.expoData[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_GVARS; i++) {
|
||||
YamlValidateName(model.gvarData[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
YamlValidateName(model.flightModeData[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_SWITCHES_FUNCTION; i++) {
|
||||
YamlValidateName(model.functionSwitchNames[i], board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_INPUTS; i++) {
|
||||
YamlValidateName(model.inputNames[i], board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
|
||||
YamlValidateName(model.limitData[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_MIXERS; i++) {
|
||||
YamlValidateName(model.mixData[i].name, board);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CPN_MAX_SENSORS; i++) {
|
||||
YamlValidateName(model.sensorData[i].label, board);
|
||||
}
|
||||
}
|
||||
|
||||
static const YamlLookupTable timerModeLut = {
|
||||
{TimerData::TIMERMODE_OFF, "OFF"},
|
||||
{TimerData::TIMERMODE_ON, "ON"},
|
||||
@@ -1092,6 +1143,8 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
|
||||
{
|
||||
if (!node.IsMap()) return false;
|
||||
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
unsigned int modelIds[CPN_MAX_MODULES];
|
||||
memset(modelIds, 0, sizeof(modelIds));
|
||||
|
||||
@@ -1151,6 +1204,7 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
|
||||
node["limitData"] >> rhs.limitData;
|
||||
|
||||
node["inputNames"] >> rhs.inputNames;
|
||||
|
||||
node["expoData"] >> rhs.expoData;
|
||||
|
||||
node["curves"] >> rhs.curves;
|
||||
@@ -1326,7 +1380,7 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
|
||||
}
|
||||
|
||||
// perform integrity checks and fix-ups
|
||||
|
||||
YamlValidateLabelsNames(rhs, board);
|
||||
rhs.sortMixes(); // critical for Companion and radio that mix lines are in sequence
|
||||
|
||||
return true;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "yaml_ops.h"
|
||||
#include "labelvalidator.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
SemanticVersion radioSettingsVersion;
|
||||
SemanticVersion modelSettingsVersion;
|
||||
@@ -57,6 +59,32 @@ void operator >> (const YAML::Node& node, bool& value)
|
||||
}
|
||||
}
|
||||
|
||||
void YamlValidateLabel(QString &input)
|
||||
{
|
||||
LabelValidator *lv = new LabelValidator();
|
||||
|
||||
if (!lv->isValid(input)) {
|
||||
lv->fixup(input);
|
||||
input = input.trimmed();
|
||||
}
|
||||
|
||||
delete lv;
|
||||
}
|
||||
|
||||
void YamlValidateName(char *input, Board::Type board)
|
||||
{
|
||||
NameValidator *nv = new NameValidator(board);
|
||||
QString in(input);
|
||||
|
||||
if (!nv->isValid(in)) {
|
||||
nv->fixup(in);
|
||||
in = in.trimmed();
|
||||
}
|
||||
|
||||
strcpy(input, in.toLatin1().data());
|
||||
delete nv;
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
|
||||
std::string LookupValue(const YamlLookupTable& lut, const int& value)
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include "helpers.h"
|
||||
#include "boards.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <QString>
|
||||
#include "helpers.h"
|
||||
|
||||
typedef std::pair<int, std::string> YamlLookupTableElmt;
|
||||
typedef std::vector<YamlLookupTableElmt> YamlLookupTable;
|
||||
@@ -122,6 +124,9 @@ void operator>>(const YAML::Node& node, T (&value)[N])
|
||||
}
|
||||
}
|
||||
|
||||
void YamlValidateName(char *input, Board::Type board);
|
||||
void YamlValidateLabel(QString &input);
|
||||
|
||||
namespace YAML {
|
||||
|
||||
std::string LookupValue(const YamlLookupTable& lut, const int& value);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "yaml_ops.h"
|
||||
|
||||
const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second is relevant channel out
|
||||
1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
|
||||
@@ -836,6 +837,7 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_STICKS && i < Boards::getCapability(board, Board::Sticks); i++) {
|
||||
inputConfig[i].type = Board::AIT_STICK;
|
||||
YamlValidateName(stickName[i], board);
|
||||
strncpy(inputConfig[i].name, stickName[i], HARDWARE_NAME_LEN);
|
||||
}
|
||||
|
||||
@@ -843,6 +845,7 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)
|
||||
int idx = Boards::getInputPotIndex(i, board);
|
||||
if (idx >= 0) {
|
||||
inputConfig[idx].type = Board::AIT_FLEX;
|
||||
YamlValidateName(potName[i], board);
|
||||
strncpy(inputConfig[idx].name, potName[i], HARDWARE_NAME_LEN);
|
||||
int ft = std::stoi(DataHelpers::getStringTagMappingTag(potTypesConversionTable, potConfig[i]));
|
||||
if (ft > -1)
|
||||
@@ -854,6 +857,7 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)
|
||||
int idx = Boards::getInputSliderIndex(i, board);
|
||||
if (idx >= 0) {
|
||||
inputConfig[idx].type = Board::AIT_FLEX;
|
||||
YamlValidateName(sliderName[i], board);
|
||||
strncpy(inputConfig[idx].name, sliderName[i], HARDWARE_NAME_LEN);
|
||||
int ft = std::stoi(DataHelpers::getStringTagMappingTag(sliderTypesConversionTable, sliderConfig[i]));
|
||||
if (ft > -1)
|
||||
@@ -869,6 +873,7 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)
|
||||
|
||||
for (int i = 0; i < CPN_MAX_SWITCHES && i < Boards::getCapability(board, Board::Switches); i++) {
|
||||
switchConfig[i].type = (Board::SwitchType)swtchConfig[i];
|
||||
YamlValidateName(swtchName[i], board);
|
||||
strncpy(switchConfig[i].name, swtchName[i], HARDWARE_NAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +46,6 @@ class AbstractStaticItemModel;
|
||||
constexpr char AIM_MODELDATA_TRAINERMODE[] {"modeldata.trainermode"};
|
||||
constexpr char AIM_MODELDATA_FUNCSWITCHCONFIG[] {"modeldata.funcswitchconfig"};
|
||||
constexpr char AIM_MODELDATA_FUNCSWITCHSTART[] {"modeldata.funcswitchstart"};
|
||||
constexpr int LABEL_LENGTH=16;
|
||||
|
||||
#define CHAR_FOR_NAMES " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
|
||||
#define CHAR_FOR_NAMES_REGEX "[ A-Za-z0-9_.-,\"]*"
|
||||
|
||||
class RSSIAlarmData {
|
||||
public:
|
||||
@@ -87,6 +83,7 @@ enum TrainerMode {
|
||||
TRAINER_MODE_LAST = TRAINER_MODE_MULTI
|
||||
};
|
||||
|
||||
#define MODEL_NAME_LEN 15
|
||||
#define INPUT_NAME_LEN 4
|
||||
#define CPN_MAX_BITMAP_LEN 14
|
||||
|
||||
@@ -125,7 +122,7 @@ class ModelData {
|
||||
|
||||
char semver[8 + 1];
|
||||
bool used;
|
||||
char name[15+1];
|
||||
char name[MODEL_NAME_LEN + 1];
|
||||
char filename[16+1];
|
||||
char labels[100];
|
||||
int modelIndex; // Companion only, temporary index position managed by data model.
|
||||
|
||||
@@ -109,8 +109,8 @@ void RadioData::convert(RadioDataConversionState & cstate)
|
||||
void RadioData::addLabel(QString label)
|
||||
{
|
||||
label = unEscapeCSV(label);
|
||||
// Truncate possible UTF-8 to 16char maximum
|
||||
QByteArray output = label.toUtf8();
|
||||
// Truncate possible UTF-8 to 16 char maximum
|
||||
QByteArray output = label.toLatin1();
|
||||
if (output.size() > LABEL_LENGTH) {
|
||||
int truncateAt = 0;
|
||||
for (int i = LABEL_LENGTH; i > 0; i--) {
|
||||
@@ -135,12 +135,12 @@ bool RadioData::deleteLabel(QString label)
|
||||
|
||||
// Remove labels in the models
|
||||
for(auto& model : models) {
|
||||
QStringList modelLabels = fromCSV(QString::fromUtf8(model.labels));
|
||||
QStringList modelLabels = fromCSV(QString::fromLatin1(model.labels));
|
||||
if (modelLabels.indexOf(label) >= 0) {
|
||||
deleted = true;
|
||||
modelLabels.removeAll(label);
|
||||
}
|
||||
strcpy(model.labels, toCSV(modelLabels).toUtf8().data());
|
||||
strcpy(model.labels, toCSV(modelLabels).toLatin1().data());
|
||||
}
|
||||
|
||||
// Remove the label from the global list
|
||||
@@ -186,8 +186,8 @@ bool RadioData::renameLabel(QString from, QString to)
|
||||
if (ind != -1) {
|
||||
modelLabels.replace(ind, csvTo);
|
||||
QString outputcsv = QString(modelLabels.join(','));
|
||||
if (outputcsv.toUtf8().size() < (int)sizeof(model.labels)) {
|
||||
strcpy(model.labels, outputcsv.toUtf8().data());
|
||||
if (outputcsv.toLatin1().size() < (int)sizeof(model.labels)) {
|
||||
strcpy(model.labels, outputcsv.toLatin1().data());
|
||||
} else { // Shouldn't ever get here, from check above
|
||||
success = false;
|
||||
throw std::length_error(model.name);
|
||||
@@ -231,10 +231,10 @@ bool RadioData::addLabelToModel(int index, QString label)
|
||||
char *modelLabelCsv = models[index].labels;
|
||||
// Make sure it will fit
|
||||
if (strlen(modelLabelCsv) + label.size() + 1 < sizeof(models[index].labels)-1) {
|
||||
QStringList modelLabels = QString::fromUtf8(modelLabelCsv).split(',', Qt::SkipEmptyParts);
|
||||
QStringList modelLabels = QString::fromLatin1(modelLabelCsv).split(',', Qt::SkipEmptyParts);
|
||||
if (modelLabels.indexOf(label) == -1) {
|
||||
modelLabels.append(label);
|
||||
strcpy(models[index].labels, QString(modelLabels.join(',')).toUtf8().data());
|
||||
strcpy(models[index].labels, QString(modelLabels.join(',')).toLatin1().data());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -246,10 +246,10 @@ bool RadioData::removeLabelFromModel(int index, QString label)
|
||||
{
|
||||
if ((unsigned int)index >= models.size()) return false;
|
||||
|
||||
QStringList lbls = fromCSV(QString::fromUtf8(models[index].labels));
|
||||
QStringList lbls = fromCSV(QString::fromLatin1(models[index].labels));
|
||||
if (lbls.indexOf(label) >= 0) {
|
||||
lbls.removeAll(label);
|
||||
strcpy(models[index].labels, toCSV(lbls).toUtf8().data());
|
||||
strcpy(models[index].labels, toCSV(lbls).toLatin1().data());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -342,4 +342,3 @@ AbstractStaticItemModel * RadioData::modelSortOrderItemModel()
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
// identiying names of static abstract item models
|
||||
constexpr char AIM_RADIO_MODEL_SORT_ORDER[] {"radio.modelsortorder"};
|
||||
|
||||
constexpr int LABEL_LENGTH = 16;
|
||||
|
||||
class RadioDataConversionState;
|
||||
class AbstractStaticItemModel;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "compounditemmodels.h"
|
||||
#include "filtereditemmodels.h"
|
||||
#include "autocombobox.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
GeneralSetupPanel::GeneralSetupPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
GeneralPanel(parent, generalSettings, firmware),
|
||||
@@ -287,8 +288,7 @@ ui(new Ui::GeneralSetup)
|
||||
ui->pwrOnDelay->hide();
|
||||
}
|
||||
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
ui->registrationId->setValidator(new QRegExpValidator(rx, this));
|
||||
ui->registrationId->setValidator(new NameValidator(board, this));
|
||||
ui->registrationId->setMaxLength(REGISTRATION_ID_LEN);
|
||||
|
||||
setValues();
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "autodoublespinbox.h"
|
||||
#include "autobitmappedcombobox.h"
|
||||
#include "autobitmappedcheckbox.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QGridLayout>
|
||||
@@ -212,6 +213,7 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
addLabel(tr("Bluetooth"));
|
||||
|
||||
AutoComboBox *bluetoothMode = new AutoComboBox(this);
|
||||
bluetoothMode->setValidator(new NameValidator(board, this));
|
||||
bluetoothMode->setModel(editorItemModels->getItemModel(btmodelid));
|
||||
bluetoothMode->setField(generalSettings.bluetoothMode, this);
|
||||
params->append(bluetoothMode);
|
||||
@@ -414,6 +416,7 @@ void HardwarePanel::addStick(int index)
|
||||
addLabel(Boards::getInputName(index, board));
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setValidator(new NameValidator(board, this));
|
||||
name->setField(config.name, HARDWARE_NAME_LEN, this);
|
||||
params->append(name);
|
||||
addParams();
|
||||
@@ -426,6 +429,7 @@ void HardwarePanel::addFlex(int index)
|
||||
addLabel(Boards::getInputName(index, board));
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setValidator(new NameValidator(board, this));
|
||||
name->setField(config.name, HARDWARE_NAME_LEN, this);
|
||||
params->append(name);
|
||||
|
||||
@@ -467,6 +471,7 @@ void HardwarePanel::addSwitch(int index)
|
||||
addLabel(Boards::getSwitchName(index));
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setValidator(new NameValidator(board, this));
|
||||
name->setField(config.name, HARDWARE_NAME_LEN, this);
|
||||
params->append(name);
|
||||
|
||||
|
||||
+27
-43
@@ -1,4 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "labels.h"
|
||||
#include "radiodata.h"
|
||||
|
||||
LabelsModel::LabelsModel(QSortFilterProxyModel * modelsListProxyModel,
|
||||
QItemSelectionModel *selectionModel,
|
||||
@@ -241,48 +263,10 @@ QModelIndex LabelsModel::getDataIndex(QModelIndex viewIndex) const
|
||||
return modelsListProxyModel->mapToSource(viewIndex);
|
||||
}
|
||||
|
||||
|
||||
QValidator::State LabelValidator::validate(QString &label, int &pos) const
|
||||
QWidget * LabelEditTextDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
{
|
||||
Q_UNUSED(pos)
|
||||
QString lbl = RadioData::escapeCSV(label);
|
||||
|
||||
if (lbl.toUtf8().size() > LABEL_LENGTH)
|
||||
return QValidator::Invalid;
|
||||
|
||||
if(lbl.contains('\\') || // TODO: Fix me to allow all, requires FW changes
|
||||
lbl.contains('\"') ||
|
||||
lbl.contains(':') ||
|
||||
lbl.contains('-') ||
|
||||
lbl.contains('\''))
|
||||
return QValidator::Invalid;
|
||||
|
||||
if(lbl.size() == 0)
|
||||
return QValidator::Intermediate;
|
||||
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
|
||||
void LabelValidator::fixup(QString &input) const
|
||||
{
|
||||
QByteArray output = input.toUtf8();
|
||||
|
||||
if (output.size() > LABEL_LENGTH) {
|
||||
int truncateAt = 0;
|
||||
for (int i = LABEL_LENGTH; i > 0; i--) {
|
||||
if ((output[i] & 0xC0) != 0x80) {
|
||||
truncateAt = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output.truncate(truncateAt);
|
||||
}
|
||||
|
||||
input = QString(output);
|
||||
input.remove('\\'); // TODO: Fix me to allow all, requires FW changes
|
||||
input.remove('\"');
|
||||
input.remove(':');
|
||||
input.remove('-');
|
||||
input.remove('\'');
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setValidator(new LabelValidator(parent));
|
||||
editor->setMaxLength(LABEL_LENGTH);
|
||||
return editor;
|
||||
}
|
||||
|
||||
+25
-20
@@ -1,16 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "labelvalidator.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QValidator>
|
||||
#include <QLineEdit>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "radiodata.h"
|
||||
|
||||
class RadioData;
|
||||
|
||||
typedef struct {
|
||||
@@ -58,27 +78,12 @@ class LabelsModel : public QAbstractItemModel
|
||||
QModelIndex getDataIndex(QModelIndex viewIndex) const;
|
||||
};
|
||||
|
||||
class LabelValidator : public QValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QValidator::State validate(QString &label, int &pos) const;
|
||||
void fixup(QString &input) const;
|
||||
};
|
||||
|
||||
class LabelEditTextDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LabelEditTextDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
|
||||
LabelEditTextDelegate(QObject * parent = nullptr) : QStyledItemDelegate(parent) {}
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setValidator(new LabelValidator);
|
||||
return editor;
|
||||
}
|
||||
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "helpers.h"
|
||||
#include "filtereditemmodels.h"
|
||||
#include "curveimagewidget.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, GeneralSettings & generalSettings,
|
||||
int min, int max, int deflt, FilteredItemModel * gvarModel, ModelPanel * panel):
|
||||
@@ -91,6 +92,8 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting
|
||||
ModelPanel(parent, model, generalSettings, firmware),
|
||||
sharedItemModels(sharedItemModels)
|
||||
{
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
chnCapability = firmware->getCapability(Outputs);
|
||||
int channelNameMaxLen = firmware->getCapability(ChannelsName);
|
||||
|
||||
@@ -107,7 +110,7 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting
|
||||
headerLabels << tr("Name");
|
||||
}
|
||||
headerLabels << tr("Subtrim") << tr("Min") << tr("Max") << tr("Direction");
|
||||
if (IS_HORUS_OR_TARANIS(firmware->getBoard()))
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
headerLabels << tr("Curve") << tr("Plot");
|
||||
if (firmware->getCapability(PPMCenter))
|
||||
headerLabels << tr("PPM Center");
|
||||
@@ -134,8 +137,7 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting
|
||||
name[i] = new QLineEdit(this);
|
||||
name[i]->setProperty("index", i);
|
||||
name[i]->setMaxLength(channelNameMaxLen);
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
name[i]->setValidator(new QRegExpValidator(rx, this));
|
||||
name[i]->setValidator(new NameValidator(board, this));
|
||||
connect(name[i], SIGNAL(editingFinished()), this, SLOT(nameEdited()));
|
||||
tableLayout->addWidget(i, col++, name[i]);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ui_expodialog.h"
|
||||
#include "filtereditemmodels.h"
|
||||
#include "helpers.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, GeneralSettings & generalSettings,
|
||||
Firmware * firmware, QString & inputName, CompoundItemModelFactory * sharedItemModels) :
|
||||
@@ -37,6 +38,7 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
Board::Type board = firmware->getBoard();
|
||||
dialogFilteredItemModels = new FilteredItemModelFactory();
|
||||
int id;
|
||||
|
||||
@@ -48,7 +50,6 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
|
||||
|
||||
RawSourceType srcType = (firmware->getCapability(VirtualInputs) ? SOURCE_TYPE_VIRTUAL_INPUT : SOURCE_TYPE_STICK);
|
||||
setWindowTitle(tr("Edit %1").arg(RawSource(srcType, ed->chn).toString(&model, &generalSettings)));
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
|
||||
id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef");
|
||||
gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100, 1.0,
|
||||
@@ -108,7 +109,7 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
|
||||
flags), "RawSource");
|
||||
ui->sourceCB->setModel(dialogFilteredItemModels->getItemModel(id));
|
||||
ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(ed->srcRaw.toValue()));
|
||||
ui->inputName->setValidator(new QRegExpValidator(rx, this));
|
||||
ui->inputName->setValidator(new NameValidator(board, this));
|
||||
ui->inputName->setText(inputName);
|
||||
}
|
||||
else {
|
||||
@@ -140,7 +141,7 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
|
||||
ui->lineName->setMaxLength(expolength);
|
||||
}
|
||||
|
||||
ui->lineName->setValidator(new QRegExpValidator(rx, this));
|
||||
ui->lineName->setValidator(new NameValidator(board, this));
|
||||
ui->lineName->setText(ed->name);
|
||||
|
||||
updateScale();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "filtereditemmodels.h"
|
||||
#include "helpers.h"
|
||||
#include "customdebug.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware,
|
||||
FilteredItemModel * rawSwitchFilteredModel):
|
||||
@@ -45,9 +46,8 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI
|
||||
trimCount = Boards::getCapability(board, Board::NumTrims);
|
||||
|
||||
// Flight mode name
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
if (fmCount) {
|
||||
ui->name->setValidator(new QRegExpValidator(rx, this));
|
||||
ui->name->setValidator(new NameValidator(board, this));
|
||||
ui->name->setMaxLength(firmware->getCapability(FlightModesName));
|
||||
connect(ui->name, SIGNAL(editingFinished()), this, SLOT(phaseName_editingFinished()));
|
||||
}
|
||||
@@ -231,6 +231,7 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI
|
||||
if (nameLen > 0) {
|
||||
gvNames[i] = new QLineEdit(ui->gvGB);
|
||||
gvNames[i]->setProperty("index", i);
|
||||
gvNames[i]->setValidator(new NameValidator(board, this));
|
||||
gvNames[i]->setMaxLength(nameLen);
|
||||
connect(gvNames[i], SIGNAL(editingFinished()), this, SLOT(GVName_editingFinished()));
|
||||
gvLayout->addWidget(gvNames[i], i + 1, col++, 1, 1);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "radiodata.h"
|
||||
#include "filtereditemmodels.h"
|
||||
#include "helpers.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, GeneralSettings & generalSettings, Firmware * firmware,
|
||||
CompoundItemModelFactory * sharedItemModels) :
|
||||
@@ -41,7 +42,6 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
|
||||
dialogFilteredItemModels = new FilteredItemModelFactory();
|
||||
int id;
|
||||
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 };
|
||||
QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 };
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
@@ -100,7 +100,7 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
|
||||
else {
|
||||
ui->mixerName->setMaxLength(namelength);
|
||||
}
|
||||
ui->mixerName->setValidator(new QRegExpValidator(rx, this));
|
||||
ui->mixerName->setValidator(new NameValidator(board, this));
|
||||
ui->mixerName->setText(md->name);
|
||||
|
||||
if (!firmware->getCapability(FlightModes)) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "checklistdialog.h"
|
||||
#include "helpers.h"
|
||||
#include "moduledata.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
@@ -55,6 +56,7 @@ TimerPanel::TimerPanel(QWidget * parent, ModelData & model, TimerData & timer, G
|
||||
if (length == 0)
|
||||
ui->name->hide();
|
||||
else {
|
||||
ui->name->setValidator(new NameValidator(firmware->getBoard(), this));
|
||||
ui->name->setField(timer.name, length, this);
|
||||
connect(ui->name, SIGNAL(currentDataChanged()), this, SLOT(onNameChanged()));
|
||||
}
|
||||
@@ -1253,11 +1255,11 @@ FunctionSwitchesPanel::FunctionSwitchesPanel(QWidget * parent, ModelData & model
|
||||
AbstractStaticItemModel *fsConfig = ModelData::funcSwitchConfigItemModel();
|
||||
AbstractStaticItemModel *fsStart = ModelData::funcSwitchStartItemModel();
|
||||
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
lock = true;
|
||||
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
|
||||
switchcnt = Boards::getCapability(firmware->getBoard(), Board::FunctionSwitches);
|
||||
switchcnt = Boards::getCapability(board, Board::FunctionSwitches);
|
||||
|
||||
for (int i = 0; i < switchcnt; i++) {
|
||||
QLabel * lblSwitchId = new QLabel(this);
|
||||
@@ -1265,7 +1267,7 @@ FunctionSwitchesPanel::FunctionSwitchesPanel(QWidget * parent, ModelData & model
|
||||
|
||||
AutoLineEdit * aleName = new AutoLineEdit(this);
|
||||
aleName->setProperty("index", i);
|
||||
aleName->setValidator(new QRegExpValidator(rx, this));
|
||||
aleName->setValidator(new NameValidator(board, this));
|
||||
aleName->setField((char *)model.functionSwitchNames[i], 3);
|
||||
|
||||
QComboBox * cboConfig = new QComboBox(this);
|
||||
@@ -1481,8 +1483,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
|
||||
|
||||
memset(modules, 0, sizeof(modules));
|
||||
|
||||
QRegExp rx(CHAR_FOR_NAMES_REGEX);
|
||||
ui->name->setValidator(new QRegExpValidator(rx, this));
|
||||
ui->name->setValidator(new NameValidator(board, this));
|
||||
ui->name->setMaxLength(firmware->getCapability(ModelName));
|
||||
|
||||
if (firmware->getCapability(HasModelImage)) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ui_telemetry_sensor.h"
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
constexpr char FIM_RAWSOURCE[] {"Raw Source"};
|
||||
constexpr char FIM_TELEALLSRC[] {"Tele All Source"};
|
||||
@@ -64,6 +65,7 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor,
|
||||
ui->numLabel->setToolTip(tr("Popup menu available"));
|
||||
ui->numLabel->setMouseTracking(true);
|
||||
connect(ui->numLabel, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_customContextMenuRequested(QPoint)));
|
||||
ui->name->setValidator(new NameValidator(firmware->getBoard(), this));
|
||||
ui->name->setField(sensor.label, SENSOR_LABEL_LEN);
|
||||
connect(ui->name, SIGNAL(currentDataChanged()), this, SLOT(on_nameDataChanged()));
|
||||
ui->id->setField(sensor.id, this);
|
||||
|
||||
@@ -19,10 +19,18 @@ set(${PROJECT_NAME}_NAMES
|
||||
curvedialog
|
||||
genericpanel
|
||||
verticalscrollarea
|
||||
textvalidator
|
||||
)
|
||||
|
||||
AddHeadersSources()
|
||||
|
||||
# these have no cpp
|
||||
set(${PROJECT_NAME}_HDRS
|
||||
${${PROJECT_NAME}_HDRS}
|
||||
namevalidator.h
|
||||
labelvalidator.h
|
||||
)
|
||||
|
||||
# AUTOMOC does not detect so manually process
|
||||
qt5_wrap_cpp(${PROJECT_NAME}_SRCS
|
||||
${${PROJECT_NAME}_HDRS}
|
||||
|
||||
@@ -39,19 +39,20 @@ AutoLineEdit::~AutoLineEdit()
|
||||
void AutoLineEdit::setField(char * field, int len, GenericPanel * panel)
|
||||
{
|
||||
m_charField = field;
|
||||
setPanel(panel);
|
||||
setValidator(new QRegExpValidator(QRegExp("[ A-Za-z0-9_.-,]*"), this));
|
||||
if (len)
|
||||
setMaxLength(len);
|
||||
updateValue();
|
||||
setFieldInit(len, panel);
|
||||
}
|
||||
|
||||
void AutoLineEdit::setField(QString & field, int len, GenericPanel * panel)
|
||||
{
|
||||
m_strField = &field;
|
||||
setFieldInit(len, panel);
|
||||
}
|
||||
|
||||
void AutoLineEdit::setFieldInit(int len, GenericPanel * panel)
|
||||
{
|
||||
setPanel(panel);
|
||||
if (len)
|
||||
setMaxLength(len);
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -47,4 +47,6 @@ class AutoLineEdit: public QLineEdit, public AutoWidget
|
||||
private:
|
||||
char *m_charField;
|
||||
QString *m_strField;
|
||||
|
||||
void setFieldInit(int len, GenericPanel * panel);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "helpers.h"
|
||||
#include "filtereditemmodels.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
float curveLinear(float x, float coeff, float yMin, float yMid, float yMax)
|
||||
{
|
||||
@@ -133,6 +134,7 @@ CurveDialog::CurveDialog(QWidget * parent, ModelData & model, const int curveIdx
|
||||
maxCurves = firmware->getCapability(NumCurves);
|
||||
maxPoints = firmware->getCapability(NumCurvePoints);
|
||||
|
||||
ui->curveName->setValidator(new NameValidator(firmware->getBoard(), this));
|
||||
ui->curveName->setField(curve.name, CURVEDATA_NAME_LEN);
|
||||
connect(ui->curveName, &AutoLineEdit::currentDataChanged, this, &CurveDialog::on_curveNameChanged);
|
||||
on_curveNameChanged();
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "textvalidator.h"
|
||||
|
||||
constexpr char LABEL_VALID_PATTERN[] {"[ A-Za-z0-9\\_\\,\\.\\+\\/\\*\\=\\%\\!\\?\\#\\<\\>\\@\\$\\(\\)\\{\\}\\[\\]\\;]*"};
|
||||
|
||||
class LabelValidator : public TextValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LabelValidator(QObject * parent = nullptr) : TextValidator(parent, LABEL_VALID_PATTERN) {}
|
||||
virtual ~LabelValidator() {}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "boards.h"
|
||||
#include "textvalidator.h"
|
||||
|
||||
// characters supportd by B&W radio firmware gui editor
|
||||
constexpr char NAME_VALID_PATTERN_BW[] {"[ A-Za-z0-9\\-]*"};
|
||||
// characters supported by color radio firmware keyboard widget
|
||||
constexpr char NAME_VALID_PATTERN_COLOR[] {"[ A-Za-z0-9\\-\\_\\,\\.\"\\+\\/\\*\\=\\%\\!\\?\\#\\<\\>\\@\\$\\(\\)\\{\\}\\[\\]\\;\\:\\']*"};
|
||||
|
||||
class NameValidator : public TextValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NameValidator(Board::Type board, QObject * parent = nullptr) :
|
||||
TextValidator(parent, Boards::getCapability(board, Board::HasColorLcd) ? NAME_VALID_PATTERN_COLOR : NAME_VALID_PATTERN_BW) {}
|
||||
virtual ~NameValidator() {}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "textvalidator.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
TextValidator::TextValidator(QObject * parent, const QString &pattern, const QChar invalidRepl, QRegularExpression::PatternOptions options):
|
||||
QRegularExpressionValidator(parent),
|
||||
invalidRepl(invalidRepl)
|
||||
{
|
||||
regexp.setPattern(pattern);
|
||||
regexp.setPatternOptions(options);
|
||||
|
||||
if (!regexp.isValid())
|
||||
qDebug() << "Error - Pattern:" << regexp.pattern() << "Error msg:" << regexp.errorString() << "Error offset:" << regexp.patternErrorOffset();
|
||||
|
||||
if (!isValid(invalidRepl))
|
||||
qDebug() << "Error - Replacement character: '" << invalidRepl << "' is not valid for pattern:" << regexp.pattern();
|
||||
|
||||
setRegularExpression(regexp);
|
||||
}
|
||||
|
||||
void TextValidator::fixup(QString &input) const
|
||||
{
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
QRegularExpressionMatch match = regexp.match(input.at(i));
|
||||
if (match.captured() != input.at(i)) // cannot rely on hasMatch
|
||||
input.replace(i, 1, invalidRepl); // replacement character MUST be valid for regexp to avoid possible loop condition
|
||||
}
|
||||
|
||||
input = input.trimmed();
|
||||
}
|
||||
|
||||
bool TextValidator::isValid(const QString &input) const
|
||||
{
|
||||
QRegularExpressionMatch match = regexp.match(input);
|
||||
return input == match.captured();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "boards.h"
|
||||
|
||||
#include <QRegularExpressionValidator>
|
||||
|
||||
class TextValidator : public QRegularExpressionValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TextValidator(QObject * parent, const QString &pattern, const QChar invalidRepl = QChar(' '),
|
||||
QRegularExpression::PatternOptions options = QRegularExpression::NoPatternOption);
|
||||
virtual ~TextValidator() {}
|
||||
|
||||
void fixup(QString &input) const;
|
||||
virtual bool isValid(const QString &input) const;
|
||||
|
||||
private:
|
||||
QChar invalidRepl;
|
||||
QRegularExpression regexp;
|
||||
};
|
||||
|
||||
@@ -76,13 +76,13 @@ void WizMix::addMix(ModelData &model, Input input, int weight, int channel, int
|
||||
}
|
||||
else if (input==FLAPS_INPUT){
|
||||
// There ought to be some kind of constants for switches somewhere...
|
||||
maxMixSwitch((char *)"Flaps Up", model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? -SWITCH_ELE : SWITCH_SA0, weight); //Taranis-Horus SA-UP, 9X ELE-UP
|
||||
maxMixSwitch((char *)"Flaps Dn", model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? SWITCH_ELE : SWITCH_SA2, -weight); //Taranis-Horus SA-DOWN, 9X ELE-DOWN
|
||||
maxMixSwitch((char *)tr("Flaps Up").toLatin1().data(), model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? -SWITCH_ELE : SWITCH_SA0, weight); //Taranis-Horus SA-UP, 9X ELE-UP
|
||||
maxMixSwitch((char *)tr("Flaps Dn").toLatin1().data(), model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? SWITCH_ELE : SWITCH_SA2, -weight); //Taranis-Horus SA-DOWN, 9X ELE-DOWN
|
||||
|
||||
}
|
||||
else if (input==AIRBRAKES_INPUT){
|
||||
maxMixSwitch((char *)"AirbkOff", model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? -SWITCH_RUD : SWITCH_SE0, -weight); //Taranis-Horus SE-UP, 9X RUD-UP
|
||||
maxMixSwitch((char *)"AirbkOn", model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? SWITCH_RUD : SWITCH_SE2, weight); //Tatanis-Horus SE-DOWN, 9X RUD-DOWN
|
||||
maxMixSwitch((char *)tr("AirbkOff").toLatin1().data(), model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? -SWITCH_RUD : SWITCH_SE0, -weight); //Taranis-Horus SE-UP, 9X RUD-UP
|
||||
maxMixSwitch((char *)tr("AirbkOn").toLatin1().data(), model.mixData[mixIndex++], channel+1, IS_SKY9X(getCurrentBoard()) ? SWITCH_RUD : SWITCH_SE2, weight); //Tatanis-Horus SE-DOWN, 9X RUD-DOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ WizMix::operator ModelData()
|
||||
mix.swtch.index = IS_SKY9X(getCurrentBoard()) ? SWITCH_THR : SWITCH_SF0;
|
||||
mix.mltpx = MLTPX_REP;
|
||||
memset(mix.name, 0, sizeof(mix.name));
|
||||
strncpy(mix.name, "Cut", MIXDATA_NAME_LEN);
|
||||
strncpy(mix.name, tr("Cut").toLatin1().data(), MIXDATA_NAME_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ WizMix::operator ModelData()
|
||||
// Add the Flight Timer option
|
||||
if (options[FLIGHT_TIMER_OPTION] && throttleChannel >= 0){
|
||||
memset(model.timers[timerIndex].name, 0, sizeof(model.timers[timerIndex].name));
|
||||
strncpy(model.timers[timerIndex].name, "Flt", sizeof(model.timers[timerIndex].name)-1);
|
||||
strncpy(model.timers[timerIndex].name, tr("Flt").toLatin1().data(), sizeof(model.timers[timerIndex].name)-1);
|
||||
model.timers[timerIndex].mode = TimerData::TIMERMODE_START;
|
||||
timerIndex++;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ WizMix::operator ModelData()
|
||||
// Add the Throttle Timer option
|
||||
if (options[THROTTLE_TIMER_OPTION] && throttleChannel >= 0){
|
||||
memset(model.timers[timerIndex].name, 0, sizeof(model.timers[timerIndex].name));
|
||||
strncpy(model.timers[timerIndex].name, "Thr", sizeof(model.timers[timerIndex].name)-1);
|
||||
strncpy(model.timers[timerIndex].name, tr("Thr").toLatin1().data(), sizeof(model.timers[timerIndex].name)-1);
|
||||
model.timers[timerIndex].mode = TimerData::TIMERMODE_THR;
|
||||
timerIndex++;
|
||||
}
|
||||
|
||||
@@ -18,15 +18,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _WIZARDDATA_H_
|
||||
#define _WIZARDDATA_H_
|
||||
#pragma once
|
||||
|
||||
#include "eeprominterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
#define WIZ_MAX_CHANNELS 8
|
||||
// TODO use a constant common to the whole companion
|
||||
// TODO when in the wizard use the getCapacity(...) to know how long the name can be
|
||||
#define WIZ_MODEL_NAME_LENGTH 12
|
||||
|
||||
enum Input {
|
||||
NO_INPUT,
|
||||
@@ -90,11 +88,13 @@ class Channel
|
||||
void clear();
|
||||
};
|
||||
|
||||
class WizMix
|
||||
class WizMix : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
bool complete;
|
||||
char name[WIZ_MODEL_NAME_LENGTH + 1];
|
||||
char name[MODEL_NAME_LEN + 1];
|
||||
unsigned int modelId;
|
||||
const GeneralSettings & settings;
|
||||
const ModelData & originalModelData;
|
||||
@@ -111,5 +111,3 @@ class WizMix
|
||||
void maxMixSwitch(char *name, MixData &mix, int destCh, int sw, int weight);
|
||||
|
||||
};
|
||||
|
||||
#endif // _WIZARDDATA_H_
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "wizarddialog.h"
|
||||
#include "wizarddata.h"
|
||||
#include "helpers.h"
|
||||
#include "namevalidator.h"
|
||||
|
||||
WizardDialog::WizardDialog(const GeneralSettings & settings, unsigned int modelId, const ModelData & modelData, QWidget *parent):
|
||||
QWizard(parent),
|
||||
@@ -276,7 +276,10 @@ int StandardPage::nextId() const
|
||||
ModelSelectionPage::ModelSelectionPage(WizardDialog *dlg, QString image, QString title, QString text)
|
||||
: StandardPage(Page_Models, dlg, image, title, text)
|
||||
{
|
||||
Firmware *fw = getCurrentFirmware();
|
||||
nameLineEdit = new QLineEdit;
|
||||
nameLineEdit->setValidator(new NameValidator(fw->getBoard()));
|
||||
nameLineEdit->setMaxLength(fw->getCapability(ModelName));
|
||||
planeRB = new QRadioButton(tr("Plane"));
|
||||
planeRB->setChecked(true);
|
||||
multirotorRB = new QRadioButton(tr("Multirotor"));
|
||||
@@ -301,12 +304,8 @@ void ModelSelectionPage::initializePage()
|
||||
|
||||
bool ModelSelectionPage::validatePage()
|
||||
{
|
||||
//Filter and insert model name in mix data
|
||||
QString newName(nameLineEdit->text());
|
||||
newName = (newName.normalized(QString::NormalizationForm_D));
|
||||
newName = newName.replace(QRegExp("[^ A-Za-z0-9_.-,\\s]"), "");
|
||||
memset(wizDlg->mix.name, 0, sizeof(wizDlg->mix.name));
|
||||
strncpy( wizDlg->mix.name, newName.toLatin1(), sizeof(wizDlg->mix.name)-1);
|
||||
strncpy( wizDlg->mix.name, nameLineEdit->text().toLatin1(), sizeof(wizDlg->mix.name) - 1);
|
||||
|
||||
if (multirotorRB->isChecked())
|
||||
wizDlg->mix.vehicle = MULTICOPTER;
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _WIZARDDIALOG_H_
|
||||
#define _WIZARDDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "wizarddata.h"
|
||||
@@ -370,7 +369,3 @@ private:
|
||||
QString vehicleName( Vehicle );
|
||||
QString printChannel( Input, int, Input, int );
|
||||
};
|
||||
#endif // _WIZARDDIALOG_H_
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user