From 47a90ed38f998e07c15cea308c620afc20e5d126 Mon Sep 17 00:00:00 2001 From: Neil Horne Date: Tue, 7 Jun 2022 20:53:45 +1000 Subject: [PATCH] feat(cpn): Add individual model save to yml (#1968) - add save model(s) to context menu and toolbar - new storage functions to support single model write - modified yml storage format write functions - default save directory is application sd card TEMPLATES - model name used as default file name --- companion/src/mdichild.cpp | 58 +++++++++++++++++++++++++++++++ companion/src/mdichild.h | 5 +++ companion/src/storage/storage.cpp | 14 ++++++++ companion/src/storage/storage.h | 2 ++ companion/src/storage/yaml.cpp | 25 ++++++------- companion/src/storage/yaml.h | 5 +-- 6 files changed, 92 insertions(+), 17 deletions(-) diff --git a/companion/src/mdichild.cpp b/companion/src/mdichild.cpp index ab2107ecf..3b3b255e1 100644 --- a/companion/src/mdichild.cpp +++ b/companion/src/mdichild.cpp @@ -231,6 +231,7 @@ void MdiChild::setupNavigation() addAct(ACT_MDL_CPY, "copy.png", SLOT(copy()), QKeySequence::Copy); addAct(ACT_MDL_PST, "paste.png", SLOT(paste()), QKeySequence::Paste); addAct(ACT_MDL_INS, "list.png", SLOT(insert()), QKeySequence::Italic); + addAct(ACT_MDL_SAV, "save.png", SLOT(modelSave()), tr("Ctrl+Alt+S")); addAct(ACT_MDL_MOV, "arrow-right.png"); QMenu * catsMenu = new QMenu(this); @@ -338,6 +339,8 @@ void MdiChild::updateNavigation() action[ACT_MDL_PST]->setText(tr("Paste") % (numOnClipbrd ? sp % modelsAddTxt : ns)); action[ACT_MDL_INS]->setEnabled(numOnClipbrd && (hasModelSlotSelcted || catsSelected)); action[ACT_MDL_INS]->setText(tr("Insert") % QString(action[ACT_MDL_INS]->isEnabled() ? sp % modelsAddTxt : ns)); + action[ACT_MDL_SAV]->setEnabled(modelsSelected); + action[ACT_MDL_SAV]->setText(tr("Save") % (modelsSelected ? sp % modelsRemvTxt : ns)); if (hasCats && action[ACT_MDL_MOV]->menu()) { action[ACT_MDL_MOV]->setVisible(true); @@ -386,6 +389,8 @@ void MdiChild::retranslateUi() action[ACT_MDL_ADD]->setText(tr("Add Model")); action[ACT_MDL_ADD]->setIconText(tr("Model")); + action[ACT_MDL_SAV]->setText(tr("Save Model")); + action[ACT_MDL_SAV]->setIconText(tr("Save")); action[ACT_MDL_RTR]->setText(tr("Restore from Backup")); action[ACT_MDL_WIZ]->setText(tr("Model Wizard")); action[ACT_MDL_DFT]->setText(tr("Set as Default")); @@ -429,6 +434,7 @@ QList MdiChild::getEditActions(bool incCatNew) actGrp.append(getAction(ACT_MDL_INS)); actGrp.append(getAction(ACT_MDL_DUP)); actGrp.append(getAction(ACT_MDL_MOV)); + actGrp.append(getAction(ACT_MDL_SAV)); return actGrp; } @@ -1814,3 +1820,55 @@ void MdiChild::openModelPrompt(int row) return; } + +void MdiChild::modelSave() +{ + saveSelectedModels(); +} + +unsigned MdiChild::saveModels(const QVector modelIndices) +{ + unsigned saves = 0; + + foreach(const int idx, modelIndices) { + if (idx < 0 || idx >= (int)radioData.models.size()) + continue; + + const QString path(QDir::toNativeSeparators(g.profile[g.id()].sdPath() + "/TEMPLATES/" + QString(radioData.models[idx].name) + ".yml")); + qDebug() << path; + + QString filename = QFileDialog::getSaveFileName(this, tr("Save model"), path, YML_FILES_FILTER); + + if (filename.isEmpty()) + return false; + + if (QFileInfo(filename).suffix() != "yml") + return false; + + Storage storage(filename); + + if (!storage.writeModel(radioData, idx)) { + QMessageBox::critical(this, CPN_STR_TTL_ERROR, storage.error()); + return false; + } + + ++saves; + } + + return saves; +} + +bool MdiChild::saveModel(const int modelIndex) +{ + QVector list = QVector() << modelIndex; + + if (saveModels(list) == 1) + return true; + else + return false; +} + +void MdiChild::saveSelectedModels() +{ + saveModels(getSelectedModels()); +} diff --git a/companion/src/mdichild.h b/companion/src/mdichild.h index 16e0281d3..55d07020e 100644 --- a/companion/src/mdichild.h +++ b/companion/src/mdichild.h @@ -59,6 +59,7 @@ class MdiChild : public QWidget ACT_MDL_DUP, ACT_MDL_INS, ACT_MDL_MOV, + ACT_MDL_SAV, ACT_MDL_RTR, // ResToRe backup ACT_MDL_WIZ, ACT_MDL_DFT, // set as DeFaulT @@ -132,6 +133,7 @@ class MdiChild : public QWidget void categoryAdd(); void modelAdd(); void modelEdit(); + void modelSave(); void wizardEdit(); void modelDuplicate(); void onModelMoveToCategory(); @@ -175,6 +177,9 @@ class MdiChild : public QWidget void moveModelsToCategory(const QVector models, const int toCategoryId); void moveSelectedModelsToCat(const int toCategoryId); unsigned countUsedModels(const int categoryId = -1); + unsigned saveModels(const QVector modelIndices); + bool saveModel(const int modelIndex); + void saveSelectedModels(); void clearCutList(); void removeModelFromCutList(const int modelIndex); diff --git a/companion/src/storage/storage.cpp b/companion/src/storage/storage.cpp index ad7a7eabd..d62b33a2a 100644 --- a/companion/src/storage/storage.cpp +++ b/companion/src/storage/storage.cpp @@ -121,6 +121,20 @@ bool Storage::write(const RadioData & radioData) return ret; } +bool Storage::writeModel(const RadioData & radioData, const int modelIndex) +{ + bool ret = false; + foreach(StorageFactory * factory, registeredStorageFactories) { + if (factory->probe(filename)) { + StorageFormat * format = factory->instance(filename); + ret = format->writeModel(radioData, modelIndex); + delete format; + break; + } + } + return ret; +} + bool convertEEprom(const QString & sourceEEprom, const QString & destinationEEprom, const QString & firmwareFilename) { FirmwareInterface firmware(firmwareFilename); diff --git a/companion/src/storage/storage.h b/companion/src/storage/storage.h index d321aeb02..f90bbdc0f 100644 --- a/companion/src/storage/storage.h +++ b/companion/src/storage/storage.h @@ -57,6 +57,7 @@ class StorageFormat virtual ~StorageFormat() {} virtual bool load(RadioData & radioData) = 0; virtual bool write(const RadioData & radioData) = 0; + virtual bool writeModel(const RadioData & radioData, const int modelIndex) { return false; } QString error() { return _error; @@ -157,6 +158,7 @@ class Storage : public StorageFormat virtual bool load(RadioData & radioData); virtual bool write(const RadioData & radioData); + virtual bool writeModel(const RadioData & radioData, const int modelIndex); }; void registerStorageFactories(); diff --git a/companion/src/storage/yaml.cpp b/companion/src/storage/yaml.cpp index e77449ff5..f47320bcd 100644 --- a/companion/src/storage/yaml.cpp +++ b/companion/src/storage/yaml.cpp @@ -40,9 +40,9 @@ bool YamlFormat::loadFile(QByteArray & filedata) return true; } -bool YamlFormat::writeFile(const QByteArray & filedata, const QString & filename) +bool YamlFormat::writeFile(const QByteArray & filedata) { - QString path = this->filename + "/" + filename; + QString path = filename; QFile file(path); if (!file.open(QFile::WriteOnly)) { setError(tr("Error opening file %1 in write mode:\n%2.").arg(path).arg(file.errorString())); @@ -121,21 +121,16 @@ bool YamlFormat::load(RadioData & radioData) return false; } -bool YamlFormat::write(const RadioData & radioData) +bool YamlFormat::writeModel(const RadioData & radioData, const int modelIndex) { - /* Need this test in case of a new sdcard - Board::Type board = getCurrentBoard(); - if (!HAS_EEPROM_YAML(board)) { - qDebug() << "Board does not support YAML format"; + if (modelIndex < 0 || modelIndex >= (int)radioData.models.size() || radioData.models[modelIndex].isEmpty()) return false; - } - // ensure directories exist on sd card - QDir dir(filename); - dir.mkdir("RADIO"); - dir.mkdir("MODELS"); - */ + QByteArray modelData; + writeModelToYaml(radioData.models[modelIndex], modelData); - qDebug() << "Warning: format ignored - under development"; - return false; // force failure until fully developed + if (!writeFile(modelData)) + return false; + + return true; } diff --git a/companion/src/storage/yaml.h b/companion/src/storage/yaml.h index b15677b67..281cf6321 100644 --- a/companion/src/storage/yaml.h +++ b/companion/src/storage/yaml.h @@ -36,9 +36,10 @@ class YamlFormat : public StorageFormat virtual QString name() { return "yml"; } virtual bool load(RadioData & radioData); - virtual bool write(const RadioData & radioData); + virtual bool write(const RadioData & radioData) { return false; } + virtual bool writeModel(const RadioData & radioData, const int modelIndex) override; protected: bool loadFile(QByteArray & fileData); - bool writeFile(const QByteArray & fileData, const QString & fileName); + bool writeFile(const QByteArray & fileData); };