From 57c7aca2f686a340b6ea6af7f5fcedfbae4425b3 Mon Sep 17 00:00:00 2001 From: Neil Horne Date: Wed, 28 Feb 2024 12:35:57 +1100 Subject: [PATCH] fix(cpn): radio specific name and label validators (#4670) Only allows valid characters in names, drops invalid characters if present --- .../src/firmwares/edgetx/edgetxinterface.cpp | 14 ++-- .../firmwares/edgetx/yaml_generalsettings.cpp | 14 +++- .../src/firmwares/edgetx/yaml_modeldata.cpp | 56 ++++++++++++++- companion/src/firmwares/edgetx/yaml_ops.cpp | 28 ++++++++ companion/src/firmwares/edgetx/yaml_ops.h | 7 +- companion/src/firmwares/generalsettings.cpp | 5 ++ companion/src/firmwares/modeldata.h | 7 +- companion/src/firmwares/radiodata.cpp | 21 +++--- companion/src/firmwares/radiodata.h | 2 + companion/src/generaledit/generalsetup.cpp | 4 +- companion/src/generaledit/hardware.cpp | 5 ++ companion/src/labels.cpp | 70 +++++++------------ companion/src/labels.h | 45 ++++++------ companion/src/modeledit/channels.cpp | 8 ++- companion/src/modeledit/expodialog.cpp | 7 +- companion/src/modeledit/flightmodes.cpp | 5 +- companion/src/modeledit/mixerdialog.cpp | 4 +- companion/src/modeledit/setup.cpp | 13 ++-- companion/src/modeledit/telemetry.cpp | 2 + companion/src/shared/CMakeLists.txt | 8 +++ companion/src/shared/autolineedit.cpp | 13 ++-- companion/src/shared/autolineedit.h | 2 + companion/src/shared/curvedialog.cpp | 2 + companion/src/shared/labelvalidator.h | 35 ++++++++++ companion/src/shared/namevalidator.h | 41 +++++++++++ companion/src/shared/textvalidator.cpp | 57 +++++++++++++++ companion/src/shared/textvalidator.h | 44 ++++++++++++ companion/src/wizarddata.cpp | 14 ++-- companion/src/wizarddata.h | 16 ++--- companion/src/wizarddialog.cpp | 11 ++- companion/src/wizarddialog.h | 7 +- 31 files changed, 428 insertions(+), 139 deletions(-) create mode 100644 companion/src/shared/labelvalidator.h create mode 100644 companion/src/shared/namevalidator.h create mode 100644 companion/src/shared/textvalidator.cpp create mode 100644 companion/src/shared/textvalidator.h diff --git a/companion/src/firmwares/edgetx/edgetxinterface.cpp b/companion/src/firmwares/edgetx/edgetxinterface.cpp index 12aac4985..b6e9e9083 100644 --- a/companion/src/firmwares/edgetx/edgetxinterface.cpp +++ b/companion/src/firmwares/edgetx/edgetxinterface.cpp @@ -26,6 +26,7 @@ #include "yaml_ops.h" #include "yaml_generalsettings.h" #include "yaml_modeldata.h" +#include "labelvalidator.h" #include @@ -113,11 +114,14 @@ bool loadLabelsListFromYaml(RadioData::ModelLabels& labels, std::string lbl = it->first.as(); RadioData::LabelData ld; ld.name = QString::fromStdString(lbl); - if (lbls[lbl]["selected"]) - ld.selected = lbls[lbl]["selected"].as(); - else - ld.selected = false; - labels.append(ld); + YamlValidateLabel(ld.name); + if (!ld.name.isEmpty()) { + if (lbls[lbl]["selected"]) + ld.selected = lbls[lbl]["selected"].as(); + else + ld.selected = false; + labels.append(ld); + } } } diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp index 843d572a8..674045df1 100644 --- a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp @@ -32,6 +32,17 @@ #include +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::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; diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.cpp b/companion/src/firmwares/edgetx/yaml_modeldata.cpp index 0084071e1..b7c1a3279 100644 --- a/companion/src/firmwares/edgetx/yaml_modeldata.cpp +++ b/companion/src/firmwares/edgetx/yaml_modeldata.cpp @@ -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::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::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::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; diff --git a/companion/src/firmwares/edgetx/yaml_ops.cpp b/companion/src/firmwares/edgetx/yaml_ops.cpp index 4d1302c03..f26b3dcc9 100644 --- a/companion/src/firmwares/edgetx/yaml_ops.cpp +++ b/companion/src/firmwares/edgetx/yaml_ops.cpp @@ -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) diff --git a/companion/src/firmwares/edgetx/yaml_ops.h b/companion/src/firmwares/edgetx/yaml_ops.h index 3b58b919e..f25688d8b 100644 --- a/companion/src/firmwares/edgetx/yaml_ops.h +++ b/companion/src/firmwares/edgetx/yaml_ops.h @@ -21,9 +21,11 @@ #pragma once #include +#include "helpers.h" +#include "boards.h" + #include #include -#include "helpers.h" typedef std::pair YamlLookupTableElmt; typedef std::vector 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); diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index 457ad9c1b..987afad6a 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -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); } diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h index 80f220dc4..b6b4c6ebc 100644 --- a/companion/src/firmwares/modeldata.h +++ b/companion/src/firmwares/modeldata.h @@ -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. diff --git a/companion/src/firmwares/radiodata.cpp b/companion/src/firmwares/radiodata.cpp index ff642c3ce..06f4df9ed 100644 --- a/companion/src/firmwares/radiodata.cpp +++ b/companion/src/firmwares/radiodata.cpp @@ -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; } - diff --git a/companion/src/firmwares/radiodata.h b/companion/src/firmwares/radiodata.h index 36db06466..d8612b602 100644 --- a/companion/src/firmwares/radiodata.h +++ b/companion/src/firmwares/radiodata.h @@ -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; diff --git a/companion/src/generaledit/generalsetup.cpp b/companion/src/generaledit/generalsetup.cpp index fc92d0dac..00c2c8641 100644 --- a/companion/src/generaledit/generalsetup.cpp +++ b/companion/src/generaledit/generalsetup.cpp @@ -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(); diff --git a/companion/src/generaledit/hardware.cpp b/companion/src/generaledit/hardware.cpp index 9c73924ec..58642997b 100644 --- a/companion/src/generaledit/hardware.cpp +++ b/companion/src/generaledit/hardware.cpp @@ -28,6 +28,7 @@ #include "autodoublespinbox.h" #include "autobitmappedcombobox.h" #include "autobitmappedcheckbox.h" +#include "namevalidator.h" #include #include @@ -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); diff --git a/companion/src/labels.cpp b/companion/src/labels.cpp index 6dae2457f..411097cc2 100644 --- a/companion/src/labels.cpp +++ b/companion/src/labels.cpp @@ -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; } diff --git a/companion/src/labels.h b/companion/src/labels.h index e5be7b012..312a869ba 100644 --- a/companion/src/labels.h +++ b/companion/src/labels.h @@ -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 #include #include #include -#include #include #include #include -#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; }; diff --git a/companion/src/modeledit/channels.cpp b/companion/src/modeledit/channels.cpp index 535c73bec..2e1ffb6f4 100644 --- a/companion/src/modeledit/channels.cpp +++ b/companion/src/modeledit/channels.cpp @@ -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]); } diff --git a/companion/src/modeledit/expodialog.cpp b/companion/src/modeledit/expodialog.cpp index b64e0ff9d..14a08d1df 100644 --- a/companion/src/modeledit/expodialog.cpp +++ b/companion/src/modeledit/expodialog.cpp @@ -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(); diff --git a/companion/src/modeledit/flightmodes.cpp b/companion/src/modeledit/flightmodes.cpp index cbd2dd706..92fd376ef 100644 --- a/companion/src/modeledit/flightmodes.cpp +++ b/companion/src/modeledit/flightmodes.cpp @@ -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); diff --git a/companion/src/modeledit/mixerdialog.cpp b/companion/src/modeledit/mixerdialog.cpp index 35bd7caaa..e9125b454 100644 --- a/companion/src/modeledit/mixerdialog.cpp +++ b/companion/src/modeledit/mixerdialog.cpp @@ -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)) { diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index 4f29c37ea..6059f2c67 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -29,6 +29,7 @@ #include "checklistdialog.h" #include "helpers.h" #include "moduledata.h" +#include "namevalidator.h" #include @@ -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)) { diff --git a/companion/src/modeledit/telemetry.cpp b/companion/src/modeledit/telemetry.cpp index 020da9606..1c45ab21b 100644 --- a/companion/src/modeledit/telemetry.cpp +++ b/companion/src/modeledit/telemetry.cpp @@ -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); diff --git a/companion/src/shared/CMakeLists.txt b/companion/src/shared/CMakeLists.txt index 77f2f47ef..52df91c58 100644 --- a/companion/src/shared/CMakeLists.txt +++ b/companion/src/shared/CMakeLists.txt @@ -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} diff --git a/companion/src/shared/autolineedit.cpp b/companion/src/shared/autolineedit.cpp index 79e92d482..4f13fe796 100644 --- a/companion/src/shared/autolineedit.cpp +++ b/companion/src/shared/autolineedit.cpp @@ -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(); } diff --git a/companion/src/shared/autolineedit.h b/companion/src/shared/autolineedit.h index be1cccaa3..3495587d1 100644 --- a/companion/src/shared/autolineedit.h +++ b/companion/src/shared/autolineedit.h @@ -47,4 +47,6 @@ class AutoLineEdit: public QLineEdit, public AutoWidget private: char *m_charField; QString *m_strField; + + void setFieldInit(int len, GenericPanel * panel); }; diff --git a/companion/src/shared/curvedialog.cpp b/companion/src/shared/curvedialog.cpp index 485e85573..76fca7bec 100644 --- a/companion/src/shared/curvedialog.cpp +++ b/companion/src/shared/curvedialog.cpp @@ -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(); diff --git a/companion/src/shared/labelvalidator.h b/companion/src/shared/labelvalidator.h new file mode 100644 index 000000000..aa7828ede --- /dev/null +++ b/companion/src/shared/labelvalidator.h @@ -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() {} +}; diff --git a/companion/src/shared/namevalidator.h b/companion/src/shared/namevalidator.h new file mode 100644 index 000000000..2b4dff10b --- /dev/null +++ b/companion/src/shared/namevalidator.h @@ -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() {} +}; + diff --git a/companion/src/shared/textvalidator.cpp b/companion/src/shared/textvalidator.cpp new file mode 100644 index 000000000..b74ea80f0 --- /dev/null +++ b/companion/src/shared/textvalidator.cpp @@ -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 + +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(); +} diff --git a/companion/src/shared/textvalidator.h b/companion/src/shared/textvalidator.h new file mode 100644 index 000000000..e8649432b --- /dev/null +++ b/companion/src/shared/textvalidator.h @@ -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 + +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; +}; + diff --git a/companion/src/wizarddata.cpp b/companion/src/wizarddata.cpp index 40b9455e7..81d2ef302 100644 --- a/companion/src/wizarddata.cpp +++ b/companion/src/wizarddata.cpp @@ -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++; } diff --git a/companion/src/wizarddata.h b/companion/src/wizarddata.h index 76b8a3db2..c122aa01a 100644 --- a/companion/src/wizarddata.h +++ b/companion/src/wizarddata.h @@ -18,15 +18,13 @@ * GNU General Public License for more details. */ -#ifndef _WIZARDDATA_H_ -#define _WIZARDDATA_H_ +#pragma once #include "eeprominterface.h" +#include + #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_ diff --git a/companion/src/wizarddialog.cpp b/companion/src/wizarddialog.cpp index 11511e7ca..30bc4d8b5 100644 --- a/companion/src/wizarddialog.cpp +++ b/companion/src/wizarddialog.cpp @@ -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; diff --git a/companion/src/wizarddialog.h b/companion/src/wizarddialog.h index 32a7c4b49..2def61501 100644 --- a/companion/src/wizarddialog.h +++ b/companion/src/wizarddialog.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _WIZARDDIALOG_H_ -#define _WIZARDDIALOG_H_ +#pragma once #include #include "wizarddata.h" @@ -370,7 +369,3 @@ private: QString vehicleName( Vehicle ); QString printChannel( Input, int, Input, int ); }; -#endif // _WIZARDDIALOG_H_ - - -