chore(cpn): Refactor component updates (#3218)
* Refactoring * Fix current release id and process dlg events * enh: Process updates dialog add select/deselect all components * Change Expression to Pattern
This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
#endif
|
||||
#include "moduledata.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "updates/updateinterface.h"
|
||||
#include "updates/updatefactories.h"
|
||||
#include "updates/updateoptionsdialog.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
@@ -462,7 +462,7 @@ void AppPreferencesDialog::initSettings()
|
||||
|
||||
btnComponentOptions[i] = new QPushButton(tr("Options"));
|
||||
connect(btnComponentOptions[i], &QPushButton::clicked, [=]() {
|
||||
UpdateOptionsDialog *dlg = new UpdateOptionsDialog(this, factories, i, false);
|
||||
UpdateOptionsDialog *dlg = new UpdateOptionsDialog(this, factories->instance(i), i, false);
|
||||
dlg->exec();
|
||||
dlg->deleteLater();
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#include "profilechooser.h"
|
||||
#include "constants.h"
|
||||
#include "updates/updates.h"
|
||||
#include "updates/updateinterface.h"
|
||||
#include "updates/updatefactories.h"
|
||||
|
||||
#include <QtGui>
|
||||
#include <QFileInfo>
|
||||
|
||||
@@ -343,7 +343,7 @@ bool ComponentData::existsOnDisk()
|
||||
return (m_settings.contains(settingsPath() % "name"));
|
||||
}
|
||||
|
||||
void ComponentData::clearRelease()
|
||||
void ComponentData::releaseClear()
|
||||
{
|
||||
releaseReset();
|
||||
releaseIdReset();
|
||||
|
||||
@@ -472,7 +472,7 @@ class ComponentData: public CompStoreObj
|
||||
};
|
||||
Q_ENUM(ReleaseChannel)
|
||||
|
||||
void clearRelease();
|
||||
void releaseClear();
|
||||
static QStringList releaseChannelsList() { return { tr("Releases"), tr("Pre-release"), tr("Nightly") } ; }
|
||||
|
||||
inline ReleaseChannel boundedReleaseChannel() const {
|
||||
|
||||
@@ -4,7 +4,14 @@ set(updates_NAMES
|
||||
updates
|
||||
updatesdialog
|
||||
updateoptionsdialog
|
||||
repomodels
|
||||
updatestatus
|
||||
updatenetwork
|
||||
repodatamodels
|
||||
repometadata
|
||||
reporeleases
|
||||
repoassets
|
||||
repo
|
||||
updateparameters
|
||||
updateinterface
|
||||
updatefirmware
|
||||
updatecompanion
|
||||
@@ -12,6 +19,7 @@ set(updates_NAMES
|
||||
updatesounds
|
||||
updatethemes
|
||||
updatemultiprotocol
|
||||
updatefactories
|
||||
chooserdialog
|
||||
)
|
||||
|
||||
@@ -30,8 +38,15 @@ set(updates_QTS
|
||||
updates.h
|
||||
updatesdialog.h
|
||||
updateoptionsdialog.h
|
||||
repomodels.h
|
||||
updatestatus.h
|
||||
updatenetwork.h
|
||||
repodatamodels.h
|
||||
reporeleases.h
|
||||
repoassets.h
|
||||
repo.h
|
||||
updateparameters.h
|
||||
updateinterface.h
|
||||
updatefactories.h
|
||||
chooserdialog.h
|
||||
)
|
||||
|
||||
|
||||
@@ -40,10 +40,6 @@ class ChooserDialog : public QDialog
|
||||
|
||||
QItemSelectionModel* selectedItems();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
Ui::ChooserDialog *ui;
|
||||
};
|
||||
|
||||
@@ -51,7 +51,6 @@ class DownloadDialog : public QDialog
|
||||
|
||||
private:
|
||||
Ui::DownloadDialog *ui;
|
||||
|
||||
QNetworkAccessManager qnam;
|
||||
QNetworkReply *reply;
|
||||
QFile *file;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 "repo.h"
|
||||
|
||||
Repo::Repo(QObject * parent, UpdateStatus * status, UpdateNetwork * network) :
|
||||
QObject(parent),
|
||||
m_status(status),
|
||||
m_network(network),
|
||||
m_releases(new RepoReleases(this, status, network)),
|
||||
m_assets(new RepoAssets(this, status, network))
|
||||
{
|
||||
connect(m_releases, &RepoReleases::idChanged, [=](const int id) {
|
||||
m_assets->onReleaseIdChanged(id);
|
||||
});
|
||||
}
|
||||
|
||||
Repo::~Repo()
|
||||
{
|
||||
delete m_assets;
|
||||
delete m_releases;
|
||||
}
|
||||
|
||||
bool Repo::getJson(const QString filename, QJsonDocument * json)
|
||||
{
|
||||
m_network->downloadJson(m_releases->urlContent(filename), json);
|
||||
|
||||
if (!m_network->isSuccess()) {
|
||||
m_status->reportProgress("Unable to download json data", QtDebugMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Repo::init(const QString & repoPath, const QString & nightly, const int resultsPerPage)
|
||||
{
|
||||
m_path = repoPath;
|
||||
m_releases->init(repoPath, nightly, resultsPerPage);
|
||||
m_assets->init(repoPath, QString(), resultsPerPage);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 "updatestatus.h"
|
||||
#include "updatenetwork.h"
|
||||
#include "reporeleases.h"
|
||||
#include "repoassets.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
constexpr char GH_API_REPOS[] {"https://api.github.com/repos"};
|
||||
constexpr char GH_API_REPOS_EDGETX[] {"https://api.github.com/repos/EdgeTX"};
|
||||
|
||||
class Repo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Repo(QObject * parent, UpdateStatus * status, UpdateNetwork * network);
|
||||
virtual ~Repo();
|
||||
|
||||
RepoAssets* const assets() const { return m_assets; }
|
||||
bool getJson(const QString filename, QJsonDocument * json);
|
||||
void init(const QString & repoPath, const QString & nightly, const int resultsPerPage);
|
||||
const QString path() const { return m_path; }
|
||||
RepoReleases* const releases() const { return m_releases; }
|
||||
|
||||
private:
|
||||
UpdateStatus* const m_status;
|
||||
UpdateNetwork* const m_network;
|
||||
RepoReleases* const m_releases;
|
||||
RepoAssets* const m_assets;
|
||||
QString m_path;
|
||||
};
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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 "repoassets.h"
|
||||
|
||||
/*
|
||||
AssetsRawItemModel
|
||||
*/
|
||||
|
||||
AssetsRawItemModel::AssetsRawItemModel() :
|
||||
RepoRawItemModel("Raw Assets")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AssetsRawItemModel::parseJsonObject(const QJsonObject & obj)
|
||||
{
|
||||
QStandardItem * item = new QStandardItem();
|
||||
|
||||
if (!obj.value("name").isUndefined()) {
|
||||
item->setText(obj.value("name").toString());
|
||||
}
|
||||
|
||||
if (!obj.value("id").isUndefined()) {
|
||||
item->setData(obj.value("id").toInt(), RIMR_Id);
|
||||
}
|
||||
|
||||
if (!obj.value("content_type").isUndefined()) {
|
||||
item->setData(obj.value("content_type").toString(), RIMR_Content);
|
||||
}
|
||||
|
||||
if (!obj.value("updated_at").isUndefined()) {
|
||||
item->setData(QDateTime::fromString(obj.value("updated_at").toString(), Qt::ISODate), RIMR_Date);
|
||||
}
|
||||
|
||||
item->setData(true, RIMR_Available);
|
||||
item->setData(0, RIMR_Flags);
|
||||
|
||||
appendRow(item);
|
||||
}
|
||||
|
||||
/*
|
||||
AssetsFilteredItemModel
|
||||
*/
|
||||
|
||||
AssetsFilteredItemModel::AssetsFilteredItemModel(AssetsRawItemModel * assetsRawItemModel) :
|
||||
RepoFilteredItemModel("Filtered Assets")
|
||||
{
|
||||
setSourceModel(assetsRawItemModel);
|
||||
}
|
||||
|
||||
const QString AssetsFilteredItemModel::contentType(const int id) const
|
||||
{
|
||||
return value(id, RIMR_Content).toString();
|
||||
}
|
||||
|
||||
const QString AssetsFilteredItemModel::copyFilter(const int id) const
|
||||
{
|
||||
return value(id, RIMR_CopyFilter).toString();
|
||||
}
|
||||
|
||||
bool AssetsFilteredItemModel::setCopyFilter(const int id, const QString filter)
|
||||
{
|
||||
return setValue(id, RIMR_CopyFilter, QVariant(filter));
|
||||
}
|
||||
|
||||
bool AssetsFilteredItemModel::setSubDirectory(const int id, const QString path)
|
||||
{
|
||||
return setValue(id, RIMR_SubDirectory, QVariant(path));
|
||||
}
|
||||
|
||||
const QString AssetsFilteredItemModel::subDirectory(const int id) const
|
||||
{
|
||||
return value(id, RIMR_SubDirectory).toString();
|
||||
}
|
||||
|
||||
/*
|
||||
RepoAssets
|
||||
*/
|
||||
|
||||
RepoAssets::RepoAssets(QObject * parent, UpdateStatus * status, UpdateNetwork * network) :
|
||||
QObject(parent),
|
||||
RepoMetaData(status, network),
|
||||
m_rawItemModel(new AssetsRawItemModel()),
|
||||
m_filteredItemModel(new AssetsFilteredItemModel(m_rawItemModel))
|
||||
{
|
||||
setModels(m_rawItemModel, m_filteredItemModel);
|
||||
}
|
||||
|
||||
const QString RepoAssets::contentType() const
|
||||
{
|
||||
return m_filteredItemModel->contentType(id());
|
||||
}
|
||||
|
||||
const QString RepoAssets::copyFilter() const
|
||||
{
|
||||
return m_filteredItemModel->copyFilter(id());
|
||||
}
|
||||
|
||||
bool RepoAssets::downloadToBuffer(const int id)
|
||||
{
|
||||
//progressMessage(tr("Download asset %1").arg(id));
|
||||
if (id > 0)
|
||||
setId(id);
|
||||
network()->downloadToBuffer(UpdateNetwork::DDT_Content, urlAsset(this->id()));
|
||||
return network()->isSuccess();
|
||||
}
|
||||
|
||||
bool RepoAssets::downloadToFile(const int row, QString & downloadDir)
|
||||
{
|
||||
getSetId(row);
|
||||
QFileInfo f(QString("%1/A%2/%3").arg(downloadDir).arg(id()).arg(name()));
|
||||
network()->downloadToFile(urlAsset(id()), f.absoluteFilePath());
|
||||
return network()->isSuccess();
|
||||
}
|
||||
|
||||
void RepoAssets::dumpItemModel(const QString modelName, const QAbstractItemModel * itemModel) const
|
||||
{
|
||||
qDebug() << "Contents of model:" << modelName;
|
||||
|
||||
if (itemModel) {
|
||||
for (int i = 0; i < itemModel->rowCount(); ++i) {
|
||||
qDebug().noquote() << "row:" << i;
|
||||
qDebug().noquote() << " name:" << itemModel->data(itemModel->index(i, 0), Qt::DisplayRole).toString();
|
||||
qDebug().noquote() << " id:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Id).toInt();
|
||||
qDebug().noquote() << " date:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Date).toDateTime();
|
||||
qDebug().noquote() << " content:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Content).toString();
|
||||
qDebug().noquote() << " copy filter:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_CopyFilter).toString();
|
||||
qDebug().noquote() << " sub dir:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_SubDirectory).toString();
|
||||
qDebug().noquote() << " flags:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Flags).toInt();
|
||||
qDebug().noquote() << " avail:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Available).toBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RepoAssets::getJson(QJsonDocument * json)
|
||||
{
|
||||
network()->downloadJson(urlAsset(id()), json);
|
||||
|
||||
if (!network()->isSuccess()) {
|
||||
status()->reportProgress("Unable to download json data", QtDebugMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RepoAssets::getJson(const QString assetName, QJsonDocument * json)
|
||||
{
|
||||
if (!getSetId(assetName))
|
||||
return false;
|
||||
|
||||
return getJson(json);
|
||||
}
|
||||
|
||||
void RepoAssets::init(const QString & repoPath,const QString & nightly, const int resultsPerPage)
|
||||
{
|
||||
RepoMetaData::init(repoPath, resultsPerPage);
|
||||
}
|
||||
|
||||
void RepoAssets::onReleaseIdChanged(const int id)
|
||||
{
|
||||
m_releaseId = id;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
bool RepoAssets::retrieveMetaDataAll()
|
||||
{
|
||||
return retrieveMetaData(RepoRawItemModel::MDT_Assets, urlAssets(m_releaseId));
|
||||
}
|
||||
|
||||
bool RepoAssets::retrieveMetaDataOne(const int id)
|
||||
{
|
||||
setId(id);
|
||||
return retrieveMetaData(RepoRawItemModel::MDT_Asset, urlAsset(id));
|
||||
}
|
||||
|
||||
bool RepoAssets::setCopyFilter(const QString filter)
|
||||
{
|
||||
return m_filteredItemModel->setCopyFilter(id(), filter);
|
||||
}
|
||||
|
||||
bool RepoAssets::setSubDirectory(const QString path)
|
||||
{
|
||||
return m_filteredItemModel->setSubDirectory(id(), path);
|
||||
}
|
||||
|
||||
const QString RepoAssets::subDirectory() const
|
||||
{
|
||||
return m_filteredItemModel->subDirectory(id());
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 "repodatamodels.h"
|
||||
#include "repometadata.h"
|
||||
|
||||
class AssetsRawItemModel : public RepoRawItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AssetsRawItemModel();
|
||||
virtual ~AssetsRawItemModel() {}
|
||||
|
||||
protected:
|
||||
friend class RepoAssets;
|
||||
|
||||
virtual void parseJsonObject(const QJsonObject & obj);
|
||||
};
|
||||
|
||||
class AssetsFilteredItemModel : public RepoFilteredItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AssetsFilteredItemModel(AssetsRawItemModel * assetsRawItemModel);
|
||||
virtual ~AssetsFilteredItemModel() {};
|
||||
|
||||
protected:
|
||||
friend class RepoAssets;
|
||||
|
||||
const QString contentType(const int id) const;
|
||||
const QString copyFilter(const int id) const;
|
||||
bool setCopyFilter(const int id, const QString filter);
|
||||
bool setSubDirectory(const int id, const QString path);
|
||||
const QString subDirectory(const int id) const;
|
||||
};
|
||||
|
||||
class RepoAssets : public QObject, public RepoMetaData
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
void onReleaseIdChanged(int id);
|
||||
|
||||
public:
|
||||
explicit RepoAssets(QObject * parent, UpdateStatus * status, UpdateNetwork * network);
|
||||
virtual ~RepoAssets() {};
|
||||
|
||||
virtual void init(const QString & repoPath, const QString & nightly, const int resultsPerPage);
|
||||
virtual bool retrieveMetaDataAll();
|
||||
virtual bool retrieveMetaDataOne(const int id);
|
||||
|
||||
const QString contentType() const;
|
||||
const QString copyFilter() const;
|
||||
bool downloadToBuffer(const int id = 0);
|
||||
bool downloadToFile(const int row, QString & downloadDir);
|
||||
bool getJson(QJsonDocument * json);
|
||||
bool getJson(const QString assetName, QJsonDocument * json);
|
||||
bool setCopyFilter(const QString filter);
|
||||
bool setSubDirectory(const QString path);
|
||||
const QString subDirectory() const;
|
||||
|
||||
signals:
|
||||
void idChanged(int id);
|
||||
|
||||
private:
|
||||
AssetsRawItemModel* const m_rawItemModel;
|
||||
AssetsFilteredItemModel* const m_filteredItemModel;
|
||||
int m_releaseId;
|
||||
|
||||
virtual void dumpItemModel(const QString modelName, const QAbstractItemModel * itemModel) const;
|
||||
};
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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 "repodatamodels.h"
|
||||
#include "constants.h"
|
||||
|
||||
/*
|
||||
RepoRawItemModel
|
||||
*/
|
||||
|
||||
RepoRawItemModel::RepoRawItemModel(QString name) :
|
||||
QStandardItemModel(),
|
||||
RepoItemModelBase(name)
|
||||
{
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void RepoRawItemModel::invalidate()
|
||||
{
|
||||
clear();
|
||||
setRefreshRequired(true);
|
||||
}
|
||||
|
||||
void RepoRawItemModel::parseAll(QJsonDocument * json)
|
||||
{
|
||||
invalidate();
|
||||
|
||||
if (json->isArray()) {
|
||||
const QJsonArray &array = json->array();
|
||||
foreach (const QJsonValue &v, array)
|
||||
{
|
||||
if (v.isObject()) {
|
||||
const QJsonObject &obj = v.toObject();
|
||||
parseJsonObject(obj);
|
||||
}
|
||||
}
|
||||
setRefreshRequired(false);
|
||||
}
|
||||
}
|
||||
|
||||
void RepoRawItemModel::parseMetaData(const int mdt, QJsonDocument * json)
|
||||
{
|
||||
switch (mdt) {
|
||||
case MDT_Asset:
|
||||
case MDT_Release:
|
||||
parseOne(json);
|
||||
break;
|
||||
case MDT_Assets:
|
||||
case MDT_Releases:
|
||||
parseAll(json);
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Unexpected meta data type" << mdt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RepoRawItemModel::parseOne(QJsonDocument * json)
|
||||
{
|
||||
invalidate();
|
||||
|
||||
if (json->isObject()) {
|
||||
const QJsonObject &obj = json->object();
|
||||
parseJsonObject(obj);
|
||||
setRefreshRequired(false);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString RepoRawItemModel::typeToString(const int val)
|
||||
{
|
||||
const QStringList strl = { "Asset", "Assets", "Release", "Releases" };
|
||||
return strl.value(val, CPN_STR_UNKNOWN_ITEM);
|
||||
}
|
||||
|
||||
void RepoRawItemModel::update()
|
||||
{
|
||||
for (int i = 0; i < rowCount(); ++i)
|
||||
setDynamicItemData(item(i));
|
||||
}
|
||||
|
||||
/*
|
||||
RepoFilteredItemModel
|
||||
*/
|
||||
|
||||
RepoFilteredItemModel::RepoFilteredItemModel(QString name) :
|
||||
QSortFilterProxyModel(),
|
||||
RepoItemModelBase(name)
|
||||
{
|
||||
m_filterFlags = 0;
|
||||
m_filterText.setPattern("");
|
||||
m_filterText.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
||||
setFilterRole(RIMR_Available);
|
||||
setFilterKeyColumn(0);
|
||||
setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
const QString RepoFilteredItemModel::date(const int id) const
|
||||
{
|
||||
return value(id, RIMR_Date).toString();
|
||||
}
|
||||
|
||||
bool RepoFilteredItemModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
|
||||
{
|
||||
const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
|
||||
if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool())
|
||||
return false;
|
||||
|
||||
if (!m_filterFlags && m_filterText.pattern().isEmpty())
|
||||
return true;
|
||||
|
||||
if (m_filterFlags) {
|
||||
bool ok;
|
||||
const int flags = sourceModel()->data(srcIdx, RIMR_Flags).toInt(&ok);
|
||||
return (ok && (m_filterFlags & flags));
|
||||
}
|
||||
else {
|
||||
return sourceModel()->data(srcIdx, Qt::DisplayRole).toString().contains(m_filterText);
|
||||
}
|
||||
}
|
||||
|
||||
const int RepoFilteredItemModel::flags(const int id) const
|
||||
{
|
||||
return value(id, RIMR_Flags).toInt();
|
||||
}
|
||||
|
||||
const int RepoFilteredItemModel::id(const int row) const
|
||||
{
|
||||
const QModelIndex & idx = index(row, 0);
|
||||
|
||||
if (!idx.isValid())
|
||||
return 0;
|
||||
|
||||
bool ok;
|
||||
const int id = data(idx, RIMR_Id).toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
return id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int RepoFilteredItemModel::id(const QVariant & value, const Qt::MatchFlags flags, const int role) const
|
||||
{
|
||||
const QModelIndexList idxlst = match(index(0, 0), role, value, 1, flags);
|
||||
|
||||
if (!idxlst.isEmpty()) {
|
||||
bool ok;
|
||||
const int id = data(idxlst.at(0), RIMR_Id).toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
return id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QStringList RepoFilteredItemModel::list() const
|
||||
{
|
||||
QStringList strl;
|
||||
|
||||
for (int i = 0; i < rowCount(); i++)
|
||||
strl << data(index(i, 0)).toString();
|
||||
|
||||
return strl;
|
||||
}
|
||||
|
||||
const QString RepoFilteredItemModel::name(const int id) const
|
||||
{
|
||||
return value(id, Qt::DisplayRole).toString();
|
||||
}
|
||||
|
||||
void RepoFilteredItemModel::setFilterFlags(const int flags)
|
||||
{
|
||||
if (m_filterFlags != flags) {
|
||||
m_filterFlags = flags;
|
||||
m_filterText.setPattern("");
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
void RepoFilteredItemModel::setFilterPattern(const QString & pattern)
|
||||
{
|
||||
if (m_filterText.pattern() != pattern) {
|
||||
m_filterText.setPattern(pattern);
|
||||
m_filterFlags = 0;
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
bool RepoFilteredItemModel::setFlags(const int id, const int flags)
|
||||
{
|
||||
return setValue(id, RIMR_Flags, QVariant(flags));
|
||||
}
|
||||
|
||||
bool RepoFilteredItemModel::setValue(const int id, const int role, const QVariant value)
|
||||
{
|
||||
//qDebug() << "id:" << id << "role:" << role << "value:" << value;
|
||||
const QModelIndexList idxlst = match(index(0, 0), RIMR_Id, QVariant(id), 1, Qt::MatchExactly);
|
||||
|
||||
if (!idxlst.isEmpty())
|
||||
return setData(idxlst.at(0), value, role);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const QVariant RepoFilteredItemModel::value(const int id, const int role) const
|
||||
{
|
||||
//qDebug() << "id:" << id << "role:";
|
||||
const QModelIndexList idxlst = match(index(0, 0), RIMR_Id, QVariant(id), 1, Qt::MatchExactly);
|
||||
|
||||
if (!idxlst.isEmpty())
|
||||
return data(idxlst.at(0), role);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const QMap<int, QVariant> RepoFilteredItemModel::valuesMap(const int id) const
|
||||
{
|
||||
const QModelIndexList idxlst = match(index(0, 0), RIMR_Id, QVariant(id), 1, Qt::MatchExactly);
|
||||
|
||||
if (!idxlst.isEmpty())
|
||||
return itemData(idxlst.at(0));
|
||||
|
||||
return QMap<int, QVariant>();
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 <QtCore>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItem>
|
||||
#include <QJsonDocument>
|
||||
|
||||
class RepoItemModelBase
|
||||
{
|
||||
public:
|
||||
explicit RepoItemModelBase(QString name) : m_modelName(name) {}
|
||||
virtual ~RepoItemModelBase() {}
|
||||
|
||||
inline const QString modelName() const { return m_modelName; }
|
||||
|
||||
enum RepoItemModelRole {
|
||||
RIMR_Id = Qt::UserRole,
|
||||
RIMR_Date,
|
||||
RIMR_SortOrder,
|
||||
RIMR_Tag,
|
||||
RIMR_Content,
|
||||
RIMR_Available,
|
||||
RIMR_Flags,
|
||||
RIMR_CopyFilter,
|
||||
RIMR_SubDirectory
|
||||
};
|
||||
|
||||
private:
|
||||
QString m_modelName;
|
||||
};
|
||||
|
||||
class RepoRawItemModel : public QStandardItemModel, public RepoItemModelBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RepoRawItemModel(QString name);
|
||||
virtual ~RepoRawItemModel() {}
|
||||
|
||||
enum MetaDataType {
|
||||
MDT_Asset,
|
||||
MDT_Assets,
|
||||
MDT_Release,
|
||||
MDT_Releases
|
||||
};
|
||||
|
||||
static QString typeToString(const int val);
|
||||
|
||||
protected:
|
||||
friend class RepoMetaData;
|
||||
friend class RepoAssets;
|
||||
friend class RepoReleases;
|
||||
|
||||
virtual bool isAvailable(QStandardItem * item) { return true; }
|
||||
virtual void parseJsonObject(const QJsonObject & obj) = 0;
|
||||
virtual void setDynamicItemData(QStandardItem * item) {}
|
||||
|
||||
void invalidate();
|
||||
const bool isRefreshRequired() const { return m_refreshRequired; }
|
||||
void parseAll(QJsonDocument * json);
|
||||
void parseMetaData(const int mdt, QJsonDocument * json);
|
||||
void parseOne(QJsonDocument * json);
|
||||
void setRefreshRequired(const bool val) { m_refreshRequired = val; }
|
||||
void update();
|
||||
|
||||
private:
|
||||
bool m_refreshRequired;
|
||||
};
|
||||
|
||||
class RepoFilteredItemModel: public QSortFilterProxyModel, public RepoItemModelBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RepoFilteredItemModel(QString name);
|
||||
virtual ~RepoFilteredItemModel() {}
|
||||
|
||||
protected:
|
||||
friend class RepoMetaData;
|
||||
friend class RepoAssets;
|
||||
friend class RepoReleases;
|
||||
|
||||
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
|
||||
|
||||
const int count() const { return rowCount(); }
|
||||
const QString date(const int id) const;
|
||||
const int flags(const int id) const;
|
||||
const int id(const int row) const ;
|
||||
const int id(const QVariant & value, const Qt::MatchFlags flags = Qt::MatchExactly, const int role = Qt::DisplayRole) const;
|
||||
const bool isEmpty() const { return rowCount() == 0; }
|
||||
const QStringList list() const;
|
||||
const QString name(const int id) const;
|
||||
void setFilterFlags(const int flags);
|
||||
void setFilterPattern(const QString & pattern);
|
||||
bool setFlags(const int id, const int flags);
|
||||
bool setValue(const int id, const int role, const QVariant value);
|
||||
const QVariant value(const int id, const int role) const;
|
||||
const QMap<int, QVariant> valuesMap(int id) const;
|
||||
|
||||
private:
|
||||
int m_filterFlags;
|
||||
QRegularExpression m_filterText;
|
||||
};
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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 "repometadata.h"
|
||||
|
||||
RepoMetaData::RepoMetaData(UpdateStatus * status, UpdateNetwork * network) :
|
||||
m_status(status),
|
||||
m_network(network),
|
||||
m_rawItemModel(nullptr),
|
||||
m_filteredItemModel(nullptr),
|
||||
m_id(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const int RepoMetaData::count() const
|
||||
{
|
||||
return m_filteredItemModel->count();
|
||||
}
|
||||
|
||||
const QString RepoMetaData::date() const
|
||||
{
|
||||
return m_filteredItemModel->date(id());
|
||||
}
|
||||
|
||||
void RepoMetaData::dumpRawItemModel() const
|
||||
{
|
||||
dumpItemModel(m_rawItemModel->modelName(), m_rawItemModel);
|
||||
}
|
||||
|
||||
void RepoMetaData::dumpFilteredItemModel() const
|
||||
{
|
||||
dumpItemModel(m_filteredItemModel->modelName(), m_filteredItemModel);
|
||||
}
|
||||
|
||||
const int RepoMetaData::flags() const
|
||||
{
|
||||
return m_filteredItemModel->flags(id());
|
||||
}
|
||||
|
||||
int RepoMetaData::getSetId()
|
||||
{
|
||||
return getSetId(0);
|
||||
}
|
||||
|
||||
int RepoMetaData::getSetId(const int row)
|
||||
{
|
||||
return setId(m_filteredItemModel->id(row));
|
||||
}
|
||||
|
||||
int RepoMetaData::getSetId(QVariant value, Qt::MatchFlags flags, int role)
|
||||
{
|
||||
return setId(m_filteredItemModel->id(value, flags, role));
|
||||
}
|
||||
|
||||
const int RepoMetaData::id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void RepoMetaData::init(const QString & repoPath, const int resultsPerPage)
|
||||
{
|
||||
m_repoPath = repoPath;
|
||||
m_resultsPerPage = resultsPerPage;
|
||||
}
|
||||
|
||||
void RepoMetaData::invalidate()
|
||||
{
|
||||
setId(0);
|
||||
m_rawItemModel->invalidate();
|
||||
}
|
||||
|
||||
const int RepoMetaData::isEmpty() const
|
||||
{
|
||||
return m_filteredItemModel->isEmpty();
|
||||
}
|
||||
|
||||
const bool RepoMetaData::isIdValid() const
|
||||
{
|
||||
return m_id > 0;
|
||||
}
|
||||
|
||||
const QStringList RepoMetaData::list() const
|
||||
{
|
||||
return m_filteredItemModel->list();
|
||||
}
|
||||
|
||||
const QString RepoMetaData::name() const
|
||||
{
|
||||
return m_filteredItemModel->name(id());
|
||||
}
|
||||
|
||||
UpdateNetwork* const RepoMetaData::network() const
|
||||
{
|
||||
return m_network;
|
||||
}
|
||||
|
||||
const QString RepoMetaData::repoPath() const
|
||||
{
|
||||
return m_repoPath;
|
||||
}
|
||||
|
||||
const int RepoMetaData::resultsPerPage() const
|
||||
{
|
||||
return m_resultsPerPage;
|
||||
}
|
||||
|
||||
bool RepoMetaData::retrieveMetaData(const int mdt, const QString url)
|
||||
{
|
||||
if (!m_rawItemModel->isRefreshRequired())
|
||||
return true;
|
||||
|
||||
QJsonDocument *json = new QJsonDocument();
|
||||
|
||||
network()->downloadMetaData(url, json);
|
||||
|
||||
if (!network()->isSuccess()) {
|
||||
status()->reportProgress("Unable to download release asset meta data", QtDebugMsg);
|
||||
invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_rawItemModel->parseMetaData(mdt, json);
|
||||
|
||||
// set current id to first row as most methods assume a current id has been set
|
||||
getSetId();
|
||||
|
||||
delete json;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RepoMetaData::setFlags(int flags)
|
||||
{
|
||||
return m_filteredItemModel->setFlags(id(), flags);
|
||||
}
|
||||
|
||||
void RepoMetaData::setFilterFlags(int flags)
|
||||
{
|
||||
m_filteredItemModel->setFilterFlags(flags);
|
||||
}
|
||||
|
||||
void RepoMetaData::setFilterPattern(const QString & pattern)
|
||||
{
|
||||
m_filteredItemModel->setFilterPattern(pattern);
|
||||
}
|
||||
|
||||
int RepoMetaData::setId(const int id)
|
||||
{
|
||||
m_id = id;
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void RepoMetaData::setModels(RepoRawItemModel * repoRawItemModel, RepoFilteredItemModel * repoFilteredItemModel)
|
||||
{
|
||||
m_rawItemModel = repoRawItemModel;
|
||||
m_filteredItemModel = repoFilteredItemModel;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
UpdateStatus* const RepoMetaData::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
const QString RepoMetaData::urlAsset(const int assetId) const
|
||||
{
|
||||
return QString("%1/assets/%2").arg(urlReleases()).arg(assetId);
|
||||
}
|
||||
|
||||
const QString RepoMetaData::urlAssets(const int releaseId) const
|
||||
{
|
||||
return QString("%1/%2/assets").arg(urlReleases()).arg(releaseId) % (m_resultsPerPage > -1 ?
|
||||
QString("\?per_page=%1").arg(m_resultsPerPage) : "");
|
||||
}
|
||||
|
||||
const QString RepoMetaData::urlContent(const QString & filename) const
|
||||
{
|
||||
return QString("%1/contents/%2").arg(m_repoPath).arg(filename);
|
||||
}
|
||||
|
||||
const QString RepoMetaData::urlReleases() const
|
||||
{
|
||||
return QString("%1/releases").arg(m_repoPath);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 "updatestatus.h"
|
||||
#include "updatenetwork.h"
|
||||
#include "repodatamodels.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class QAbstractItemModel;
|
||||
|
||||
class RepoMetaData
|
||||
{
|
||||
public:
|
||||
explicit RepoMetaData(UpdateStatus * status, UpdateNetwork * network);
|
||||
virtual ~RepoMetaData() {}
|
||||
|
||||
virtual void init(const QString & repoPath, const QString & nightly, const int resultsPerPage) = 0;
|
||||
virtual bool retrieveMetaDataAll() = 0;
|
||||
virtual bool retrieveMetaDataOne(const int id) = 0;
|
||||
virtual int setId(const int id);
|
||||
|
||||
const int count() const;
|
||||
const QString date() const;
|
||||
void dumpRawItemModel() const;
|
||||
void dumpFilteredItemModel() const;
|
||||
const int flags() const;
|
||||
int getSetId();
|
||||
int getSetId(const int row);
|
||||
int getSetId(QVariant value, Qt::MatchFlags flags = Qt::MatchExactly, int role = Qt::DisplayRole);
|
||||
const int id() const;
|
||||
void init(const QString & repoPath, const int resultsPerPage);
|
||||
void invalidate();
|
||||
const int isEmpty() const;
|
||||
const bool isIdValid() const;
|
||||
const QStringList list() const;
|
||||
const QString name() const;
|
||||
UpdateNetwork* const network() const;
|
||||
const QString repoPath() const;
|
||||
const int resultsPerPage() const;
|
||||
bool retrieveMetaData(const int mdt, const QString url);
|
||||
bool setFlags(int flags);
|
||||
void setFilterFlags(int flags);
|
||||
void setFilterPattern(const QString & pattern);
|
||||
void setModels(RepoRawItemModel * repoRawItemModel, RepoFilteredItemModel * repoFilteredItemModel);
|
||||
UpdateStatus* const status() const;
|
||||
const QString urlAsset(const int assetId) const;
|
||||
const QString urlAssets(const int releaseId) const;
|
||||
const QString urlContent(const QString & filename) const;
|
||||
const QString urlReleases() const;
|
||||
|
||||
private:
|
||||
UpdateStatus* const m_status;
|
||||
UpdateNetwork* const m_network;
|
||||
RepoRawItemModel* m_rawItemModel;
|
||||
RepoFilteredItemModel* m_filteredItemModel;
|
||||
|
||||
QString m_repoPath;
|
||||
int m_resultsPerPage;
|
||||
int m_id;
|
||||
|
||||
virtual void dumpItemModel(const QString modelName, const QAbstractItemModel * itemModel) const = 0;
|
||||
};
|
||||
@@ -1,546 +0,0 @@
|
||||
/*
|
||||
* 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 "repomodels.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QStandardItem>
|
||||
#include <QJsonDocument>
|
||||
|
||||
QString metaDataTypeToString(MetaDataType val)
|
||||
{
|
||||
switch ((int)val) {
|
||||
case MDT_Release:
|
||||
return "Release";
|
||||
case MDT_Releases:
|
||||
return "Releases";
|
||||
case MDT_Asset:
|
||||
return "Asset";
|
||||
case MDT_ReleaseAssets:
|
||||
return "Release Assets";
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
ReleasesItemModel
|
||||
*/
|
||||
|
||||
ReleasesItemModel::ReleasesItemModel() :
|
||||
UpdatesItemModel("Releases"),
|
||||
m_settingsIdx(-1),
|
||||
m_nightlyName(""),
|
||||
m_releaseChannel(-1),
|
||||
m_refreshRequired(true)
|
||||
{
|
||||
setSortRole(UpdatesItemModel::IMDR_SortOrder);
|
||||
}
|
||||
|
||||
void ReleasesItemModel::setReleaseChannel(const int channel)
|
||||
{
|
||||
if (m_releaseChannel != channel) {
|
||||
m_releaseChannel = channel;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void ReleasesItemModel::parseMetaData(const int mdt, QJsonDocument * jsonDoc)
|
||||
{
|
||||
json = jsonDoc;
|
||||
|
||||
switch (mdt) {
|
||||
case MDT_Release:
|
||||
parseRelease();
|
||||
break;
|
||||
case MDT_Releases:
|
||||
parseReleases();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ReleasesItemModel::parseRelease()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (json->isObject()) {
|
||||
const QJsonObject &obj = json->object();
|
||||
parseJsonObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void ReleasesItemModel::parseReleases()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (json->isArray()) {
|
||||
const QJsonArray &array = json->array();
|
||||
foreach (const QJsonValue &v, array)
|
||||
{
|
||||
if (v.isObject()) {
|
||||
const QJsonObject &obj = v.toObject();
|
||||
parseJsonObject(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort(0, Qt::DescendingOrder);
|
||||
m_refreshRequired = false;
|
||||
}
|
||||
|
||||
void ReleasesItemModel::parseJsonObject(const QJsonObject & obj)
|
||||
{
|
||||
QStandardItem * item = new QStandardItem();
|
||||
|
||||
QString tag = QString();
|
||||
bool prerelease = false;
|
||||
|
||||
if (!obj.value("name").isUndefined()) {
|
||||
item->setText(obj.value("name").toString());
|
||||
}
|
||||
|
||||
if (!obj.value("id").isUndefined()) {
|
||||
item->setData(obj.value("id").toInt(), UpdatesItemModel::IMDR_Id);
|
||||
}
|
||||
|
||||
if (!obj.value("tag_name").isUndefined()) {
|
||||
tag = obj.value("tag_name").toString();
|
||||
item->setData(tag, UpdatesItemModel::IMDR_Tag);
|
||||
}
|
||||
|
||||
if (!obj.value("prerelease").isUndefined()) {
|
||||
prerelease = obj.value("prerelease").toBool();
|
||||
item->setData(prerelease, UpdatesItemModel::IMDR_Prerelease);
|
||||
}
|
||||
|
||||
if (!obj.value("created_at").isUndefined()) {
|
||||
item->setData(QDateTime::fromString(obj.value("created_at").toString(), Qt::ISODate), UpdatesItemModel::IMDR_Date);
|
||||
}
|
||||
|
||||
setDynamicItemData(item);
|
||||
|
||||
SemanticVersion sv;
|
||||
|
||||
if (tag.toLower() == m_nightlyName)
|
||||
sv.fromString("255.255.255");
|
||||
else
|
||||
sv.fromString(tag);
|
||||
|
||||
if (sv.isValid())
|
||||
item->setData(sv.toInt(), UpdatesItemModel::IMDR_SortOrder);
|
||||
else
|
||||
item->setData(item->data(IMDR_Date).toInt(), UpdatesItemModel::IMDR_SortOrder);
|
||||
|
||||
appendRow(item);
|
||||
}
|
||||
|
||||
void ReleasesItemModel::setDynamicItemData(QStandardItem * item)
|
||||
{
|
||||
item->setData(isReleaseAvailable(item), UpdatesItemModel::IMDR_Available);
|
||||
}
|
||||
|
||||
void ReleasesItemModel::update()
|
||||
{
|
||||
for (int i = 0; i < rowCount(); ++i)
|
||||
setDynamicItemData(item(i));
|
||||
}
|
||||
|
||||
bool ReleasesItemModel::isReleaseAvailable(QStandardItem * item)
|
||||
{
|
||||
if (item->data(IMDR_Prerelease).toBool()) {
|
||||
if (m_releaseChannel == ComponentData::RELEASE_CHANNEL_STABLE) {
|
||||
//qDebug() << "Release channel stable" << tagname << "is pre-release" ;
|
||||
return false;
|
||||
}
|
||||
else if (m_releaseChannel == ComponentData::RELEASE_CHANNEL_PRERELEASE &&
|
||||
item->data(IMDR_Tag).toString().toLower() == m_nightlyName) {
|
||||
//qDebug() << "Release channel pre-release" << tagname << "is nightly" ;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//qDebug() << "Release available:" << tagname;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
AssetsItemModel
|
||||
*/
|
||||
|
||||
AssetsItemModel::AssetsItemModel() :
|
||||
UpdatesItemModel("Assets")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AssetsItemModel::parseMetaData(int mdt, QJsonDocument * jsonDoc)
|
||||
{
|
||||
json = jsonDoc;
|
||||
|
||||
switch (mdt) {
|
||||
case MDT_Asset:
|
||||
parseAsset();
|
||||
break;
|
||||
case MDT_ReleaseAssets:
|
||||
parseReleaseAssets();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsItemModel::parseAsset()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (json->isObject()) {
|
||||
const QJsonObject &obj = json->object();
|
||||
parseJsonObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsItemModel::parseReleaseAssets()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (json->isArray()) {
|
||||
const QJsonArray &array = json->array();
|
||||
foreach (const QJsonValue &v, array)
|
||||
{
|
||||
if (v.isObject()) {
|
||||
const QJsonObject &obj = v.toObject();
|
||||
parseJsonObject(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort(0);
|
||||
}
|
||||
|
||||
void AssetsItemModel::parseJsonObject(const QJsonObject & obj)
|
||||
{
|
||||
QStandardItem * item = new QStandardItem();
|
||||
|
||||
if (!obj.value("name").isUndefined()) {
|
||||
item->setText(obj.value("name").toString());
|
||||
}
|
||||
|
||||
if (!obj.value("id").isUndefined()) {
|
||||
item->setData(obj.value("id").toInt(), UpdatesItemModel::IMDR_Id);
|
||||
}
|
||||
|
||||
if (!obj.value("content_type").isUndefined()) {
|
||||
item->setData(obj.value("content_type").toString(), UpdatesItemModel::IMDR_Content);
|
||||
}
|
||||
|
||||
if (!obj.value("updated_at").isUndefined()) {
|
||||
item->setData(QDateTime::fromString(obj.value("updated_at").toString(), Qt::ISODate), UpdatesItemModel::IMDR_Date);
|
||||
}
|
||||
|
||||
item->setData(true, UpdatesItemModel::IMDR_Available);
|
||||
|
||||
appendRow(item);
|
||||
}
|
||||
|
||||
/*
|
||||
UpdatesFilteredItemModel
|
||||
*/
|
||||
|
||||
UpdatesFilteredItemModel::UpdatesFilteredItemModel(UpdatesItemModel * sourceModel, QString name) :
|
||||
QSortFilterProxyModel(nullptr),
|
||||
filterFlags(0),
|
||||
m_name(name)
|
||||
{
|
||||
filterText.setPattern("");
|
||||
filterText.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
||||
setFilterRole(UpdatesItemModel::IMDR_Available);
|
||||
setFilterKeyColumn(0);
|
||||
setDynamicSortFilter(true);
|
||||
setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
void UpdatesFilteredItemModel::setFilterFlags(const int flags)
|
||||
{
|
||||
if (filterFlags != flags) {
|
||||
filterFlags = flags;
|
||||
filterText.setPattern("");
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatesFilteredItemModel::setFilterPattern(const QString & pattern)
|
||||
{
|
||||
if (filterText.pattern() != pattern) {
|
||||
filterText.setPattern(pattern);
|
||||
filterFlags = 0;
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
bool UpdatesFilteredItemModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
|
||||
{
|
||||
const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
|
||||
if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool())
|
||||
return false;
|
||||
|
||||
if (!filterFlags && filterText.pattern().isEmpty())
|
||||
return true;
|
||||
|
||||
if (filterFlags) {
|
||||
bool ok;
|
||||
const int flags = sourceModel()->data(srcIdx, UpdatesItemModel::IMDR_Flags).toInt(&ok);
|
||||
|
||||
return (ok && (!flags || (filterFlags & flags)));
|
||||
}
|
||||
else {
|
||||
return sourceModel()->data(srcIdx, Qt::DisplayRole).toString().contains(filterText);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatesFilteredItemModel::dumpContents()
|
||||
{
|
||||
qDebug() << "Contents of" << m_name;
|
||||
|
||||
for (int i = 0; i < rowCount(); ++i) {
|
||||
qDebug() << "row:" << i
|
||||
<< "text:" << data(index(i, 0), Qt::DisplayRole).toString()
|
||||
<< "id:" << data(index(i, 0), UpdatesItemModel::IMDR_Id).toInt()
|
||||
<< "date:" << data(index(i, 0), UpdatesItemModel::IMDR_Date).toDateTime()
|
||||
<< "tag:" << data(index(i, 0), UpdatesItemModel::IMDR_Tag).toString()
|
||||
<< "avail:" << data(index(i, 0), UpdatesItemModel::IMDR_Available).toBool()
|
||||
<< "flags:" << data(index(i, 0), UpdatesItemModel::IMDR_Flags).toInt()
|
||||
<< "content:" << data(index(i, 0), UpdatesItemModel::IMDR_Content).toString()
|
||||
<< "prerelease:" << data(index(i, 0), UpdatesItemModel::IMDR_Prerelease).toBool();
|
||||
}
|
||||
}
|
||||
|
||||
QMap<int, QVariant> UpdatesFilteredItemModel::itemMetaData(const int id)
|
||||
{
|
||||
const QModelIndexList idxlst = match(index(0, 0), UpdatesItemModel::IMDR_Id, QVariant(id), 1, Qt::MatchExactly);
|
||||
|
||||
if (!idxlst.isEmpty())
|
||||
return itemData(idxlst.at(0));
|
||||
|
||||
return QMap<int, QVariant>();
|
||||
}
|
||||
|
||||
QVariant UpdatesFilteredItemModel::metaDataValue(const int id, const int role)
|
||||
{
|
||||
//qDebug() << "id:" << id << "role:";
|
||||
|
||||
const QModelIndexList idxlst = match(index(0, 0), UpdatesItemModel::IMDR_Id, QVariant(id), 1, Qt::MatchExactly);
|
||||
|
||||
if (!idxlst.isEmpty())
|
||||
return data(idxlst.at(0), role);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool UpdatesFilteredItemModel::setMetaDataValue(const int id, const int role, const QVariant value)
|
||||
{
|
||||
//qDebug() << "id:" << id << "role:" << role << "value:" << value;
|
||||
|
||||
const QModelIndexList idxlst = match(index(0, 0), UpdatesItemModel::IMDR_Id, QVariant(id), 1, Qt::MatchExactly);
|
||||
|
||||
if (!idxlst.isEmpty())
|
||||
return setData(idxlst.at(0), value, role);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int UpdatesFilteredItemModel::id(const int row)
|
||||
{
|
||||
const QModelIndex & idx = index(row, 0);
|
||||
|
||||
if (!idx.isValid())
|
||||
return 0;
|
||||
|
||||
bool ok;
|
||||
const int id = data(idx, UpdatesItemModel::IMDR_Id).toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
return id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UpdatesFilteredItemModel::id(const QVariant value, const Qt::MatchFlags flags, const int role)
|
||||
{
|
||||
const QModelIndexList idxlst = match(index(0, 0), role, value, 1, flags);
|
||||
|
||||
if (!idxlst.isEmpty()) {
|
||||
bool ok;
|
||||
const int id = data(idxlst.at(0), UpdatesItemModel::IMDR_Id).toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
return id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QStringList UpdatesFilteredItemModel::list()
|
||||
{
|
||||
QStringList strl;
|
||||
|
||||
for (int i = 0; i < rowCount(); i++)
|
||||
strl << data(index(i, 0)).toString();
|
||||
|
||||
return strl;
|
||||
}
|
||||
|
||||
/*
|
||||
ReleasesFilteredItemModel
|
||||
*/
|
||||
|
||||
ReleasesFilteredItemModel::ReleasesFilteredItemModel(UpdatesItemModel * sourceModel) :
|
||||
UpdatesFilteredItemModel(sourceModel, "Filtered Releases")
|
||||
{
|
||||
setSortRole(UpdatesItemModel::IMDR_Date);
|
||||
}
|
||||
|
||||
int ReleasesFilteredItemModel::channelLatestId()
|
||||
{
|
||||
return rows() > 0 ? id(0) : 0; // assumes model sorted descending date
|
||||
}
|
||||
|
||||
/*
|
||||
AssetsFilteredItemModel
|
||||
*/
|
||||
|
||||
AssetsFilteredItemModel::AssetsFilteredItemModel(UpdatesItemModel * sourceModel) :
|
||||
UpdatesFilteredItemModel(sourceModel, "Filtered Assets")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool AssetsFilteredItemModel::setFlags(const int id, const int flags)
|
||||
{
|
||||
return setMetaDataValue(id, UpdatesItemModel::IMDR_Flags, QVariant(flags));
|
||||
}
|
||||
|
||||
bool AssetsFilteredItemModel::setSubDirectory(const int id, const QString path)
|
||||
{
|
||||
return setMetaDataValue(id, UpdatesItemModel::IMDR_SubDirectory, QVariant(path));
|
||||
}
|
||||
|
||||
bool AssetsFilteredItemModel::setCopyFilter(const int id, const QString filter)
|
||||
{
|
||||
return setMetaDataValue(id, UpdatesItemModel::IMDR_CopyFilter, QVariant(filter));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
RepoMetaData
|
||||
*/
|
||||
|
||||
RepoMetaData::RepoMetaData(QObject * parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
ReleasesMetaData
|
||||
*/
|
||||
|
||||
ReleasesMetaData::ReleasesMetaData(QObject * parent) :
|
||||
RepoMetaData(parent),
|
||||
m_id(0)
|
||||
{
|
||||
itemModel = new ReleasesItemModel();
|
||||
filteredItemModel = new ReleasesFilteredItemModel(itemModel);
|
||||
}
|
||||
|
||||
void ReleasesMetaData::init(const QString repo, const QString nightly, const int settingsIndex, const int resultsPerPage)
|
||||
{
|
||||
m_repo = repo;
|
||||
m_resultsPerPage = resultsPerPage;
|
||||
itemModel->setNightlyName(nightly);
|
||||
itemModel->setSettingsIndex(settingsIndex);
|
||||
}
|
||||
|
||||
bool ReleasesMetaData::refreshRequired()
|
||||
{
|
||||
return m_id == 0 ? true : itemModel->refreshRequired();
|
||||
}
|
||||
|
||||
int ReleasesMetaData::getSetId()
|
||||
{
|
||||
m_id = filteredItemModel->channelLatestId();
|
||||
return m_id;
|
||||
}
|
||||
|
||||
int ReleasesMetaData::getSetId(int row)
|
||||
{
|
||||
m_id = filteredItemModel->id(row);
|
||||
return m_id;
|
||||
}
|
||||
|
||||
int ReleasesMetaData::getSetId(QVariant value, Qt::MatchFlags flags, int role)
|
||||
{
|
||||
m_id = filteredItemModel->id(value, flags, role);
|
||||
return m_id;
|
||||
}
|
||||
|
||||
QString ReleasesMetaData::name()
|
||||
{
|
||||
if (m_id)
|
||||
return filteredItemModel->name(m_id);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
QString ReleasesMetaData::version()
|
||||
{
|
||||
if (m_id)
|
||||
return filteredItemModel->version(m_id);
|
||||
|
||||
return "0";
|
||||
}
|
||||
|
||||
/*
|
||||
AssetsMetaData
|
||||
*/
|
||||
|
||||
AssetsMetaData::AssetsMetaData(QObject * parent) :
|
||||
RepoMetaData(parent)
|
||||
{
|
||||
itemModel = new AssetsItemModel();
|
||||
filteredItemModel = new AssetsFilteredItemModel(itemModel);
|
||||
}
|
||||
|
||||
void AssetsMetaData::init(const QString repo, const int resultsPerPage)
|
||||
{
|
||||
m_repo = repo;
|
||||
m_resultsPerPage = resultsPerPage;
|
||||
}
|
||||
|
||||
int AssetsMetaData::getSetId(int row)
|
||||
{
|
||||
m_id = filteredItemModel->id(row);
|
||||
return m_id;
|
||||
}
|
||||
|
||||
int AssetsMetaData::getSetId(QVariant value, Qt::MatchFlags flags, int role)
|
||||
{
|
||||
m_id = filteredItemModel->id(value, flags, role);
|
||||
return m_id;
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* 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 <QtCore>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
constexpr char GITHUB_API_REPOS[] {"https://api.github.com/repos"};
|
||||
constexpr char GH_REPOS_EDGETX[] {"https://api.github.com/repos/EdgeTX"};
|
||||
|
||||
constexpr char GH_ACCEPT_HEADER_BINARY[] {"application/octet-stream"};
|
||||
constexpr char GH_ACCEPT_HEADER_METADATA[] {"application/vnd.github.v3+json"};
|
||||
constexpr char GH_ACCEPT_HEADER_RAW[] {"application/vnd.github.v3.raw"};
|
||||
|
||||
enum MetaDataType {
|
||||
MDT_Release,
|
||||
MDT_Releases,
|
||||
MDT_Asset,
|
||||
MDT_ReleaseAssets
|
||||
};
|
||||
|
||||
QString metaDataTypeToString(MetaDataType val);
|
||||
|
||||
class UpdatesItemModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ItemModelDataRoles {
|
||||
IMDR_Id = Qt::UserRole,
|
||||
IMDR_Date,
|
||||
IMDR_SortOrder,
|
||||
IMDR_Tag,
|
||||
IMDR_Prerelease,
|
||||
IMDR_Content,
|
||||
IMDR_Available,
|
||||
IMDR_Flags,
|
||||
IMDR_CopyFilter,
|
||||
IMDR_SubDirectory
|
||||
};
|
||||
Q_ENUM(ItemModelDataRoles)
|
||||
|
||||
explicit UpdatesItemModel(QString name = "") :
|
||||
QStandardItemModel(nullptr),
|
||||
json(nullptr),
|
||||
m_name(name) {}
|
||||
|
||||
virtual ~UpdatesItemModel() {}
|
||||
|
||||
protected:
|
||||
QJsonDocument * json;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
};
|
||||
|
||||
class ReleasesItemModel : public UpdatesItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ReleasesMetaData;
|
||||
|
||||
public:
|
||||
explicit ReleasesItemModel();
|
||||
virtual ~ReleasesItemModel() {}
|
||||
|
||||
void setNightlyName(const QString name) { m_nightlyName = name.toLower(); }
|
||||
void setSettingsIndex(const int index) { m_settingsIdx = index; }
|
||||
void setReleaseChannel(const int channel);
|
||||
|
||||
void parseMetaData(const int mdt, QJsonDocument * json);
|
||||
int settingsIndex() { return m_settingsIdx; }
|
||||
bool refreshRequired() { return m_refreshRequired; }
|
||||
|
||||
private:
|
||||
int m_settingsIdx;
|
||||
QString m_nightlyName;
|
||||
int m_releaseChannel;
|
||||
bool m_refreshRequired;
|
||||
|
||||
void setDynamicItemData(QStandardItem * item);
|
||||
void update();
|
||||
bool isReleaseAvailable(QStandardItem * item);
|
||||
|
||||
void parseRelease();
|
||||
void parseReleases();
|
||||
void parseJsonObject(const QJsonObject & obj);
|
||||
};
|
||||
|
||||
class AssetsItemModel : public UpdatesItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class AssetsMetaData;
|
||||
|
||||
public:
|
||||
explicit AssetsItemModel();
|
||||
virtual ~AssetsItemModel() {}
|
||||
|
||||
void parseMetaData(int mdt, QJsonDocument * json);
|
||||
|
||||
private:
|
||||
void parseAsset();
|
||||
void parseReleaseAssets();
|
||||
void parseJsonObject(const QJsonObject & obj);
|
||||
};
|
||||
|
||||
class UpdatesFilteredItemModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UpdatesFilteredItemModel(UpdatesItemModel * sourceModel, QString name = "");
|
||||
virtual ~UpdatesFilteredItemModel() {};
|
||||
|
||||
void dumpContents();
|
||||
QStringList list();
|
||||
|
||||
int id(const int row);
|
||||
int id(const QVariant value, const Qt::MatchFlags flags = Qt::MatchExactly, const int role = Qt::DisplayRole);
|
||||
int rows() { return rowCount(); }
|
||||
|
||||
QString date(const int id) { return metaDataValue(id, UpdatesItemModel::IMDR_Date).toString(); }
|
||||
QString name(const int id) { return metaDataValue(id, Qt::DisplayRole).toString(); }
|
||||
|
||||
public slots:
|
||||
void setFilterFlags(const int flags);
|
||||
void setFilterPattern(const QString & pattern);
|
||||
|
||||
signals:
|
||||
|
||||
protected:
|
||||
int filterFlags;
|
||||
QRegularExpression filterText;
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
|
||||
|
||||
QMap<int, QVariant> itemMetaData(int id);
|
||||
QVariant metaDataValue(const int id, const int role);
|
||||
bool setMetaDataValue(const int id, const int role, const QVariant value);
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
};
|
||||
|
||||
class ReleasesFilteredItemModel: public UpdatesFilteredItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
protected:
|
||||
friend class ReleasesMetaData;
|
||||
|
||||
explicit ReleasesFilteredItemModel(UpdatesItemModel * sourceModel);
|
||||
virtual ~ReleasesFilteredItemModel() {};
|
||||
|
||||
int channelLatestId();
|
||||
|
||||
bool prerelease(const int id) { return metaDataValue(id, UpdatesItemModel::IMDR_Prerelease).toBool(); }
|
||||
QString version(const int id) { return metaDataValue(id, UpdatesItemModel::IMDR_Tag).toString(); }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class AssetsFilteredItemModel : public UpdatesFilteredItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
protected:
|
||||
friend class AssetsMetaData;
|
||||
|
||||
explicit AssetsFilteredItemModel(UpdatesItemModel * sourceModel);
|
||||
virtual ~AssetsFilteredItemModel() {};
|
||||
|
||||
bool setFlags(const int id, const int flags);
|
||||
bool setSubDirectory(const int id, const QString path);
|
||||
bool setCopyFilter(const int id, const QString filter);
|
||||
|
||||
QString filename(int id) { return metaDataValue(id, Qt::DisplayRole).toString(); }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class RepoMetaData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RepoMetaData(QObject * parent);
|
||||
virtual ~RepoMetaData() {};
|
||||
|
||||
const QString urlReleases() { return QString("%1/releases").arg(m_repo); }
|
||||
const QString urlReleaseLatest() { return QString("%1/latest").arg(urlReleases()); }
|
||||
const QString urlContent(const QString & path) { return QString("%1/contents/%2").arg(m_repo).arg(path); }
|
||||
|
||||
protected:
|
||||
QString m_repo;
|
||||
int m_resultsPerPage;
|
||||
};
|
||||
|
||||
class ReleasesMetaData : public RepoMetaData
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ReleasesMetaData(QObject * parent);
|
||||
virtual ~ReleasesMetaData() {};
|
||||
|
||||
void init(const QString repo, const QString nightly, const int settingsIndex, const int resultsPerPage);
|
||||
|
||||
bool refreshRequired();
|
||||
void setReleaseChannel(const int channel) { itemModel->setReleaseChannel(channel); }
|
||||
|
||||
void setId(int id) { m_id = id; }
|
||||
int id() { return m_id; }
|
||||
|
||||
int getSetId();
|
||||
int getSetId(int row);
|
||||
int getSetId(QVariant value, Qt::MatchFlags flags = Qt::MatchExactly, int role = Qt::DisplayRole);
|
||||
|
||||
void parseMetaData(int mdt, QJsonDocument * jsonDoc) { itemModel->parseMetaData(mdt, jsonDoc); }
|
||||
|
||||
int count() { return filteredItemModel->rows(); }
|
||||
QStringList list() { return filteredItemModel->list(); }
|
||||
void dumpContentsFiltered() { filteredItemModel->dumpContents(); }
|
||||
|
||||
QString date() { return filteredItemModel->date(m_id); }
|
||||
QString name();
|
||||
bool prerelease() { return filteredItemModel->prerelease(m_id); }
|
||||
QString version();
|
||||
|
||||
const QString urlRelease() { return QString("%1/%2").arg(urlReleases()).arg(m_id); }
|
||||
|
||||
private:
|
||||
ReleasesItemModel *itemModel;
|
||||
ReleasesFilteredItemModel *filteredItemModel;
|
||||
int m_id;
|
||||
};
|
||||
|
||||
class AssetsMetaData : public RepoMetaData
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AssetsMetaData(QObject * parent);
|
||||
virtual ~AssetsMetaData() {};
|
||||
|
||||
void init(const QString repo, const int resultsPerPage);
|
||||
|
||||
void setId(int id) { m_id = id; }
|
||||
int id() { return m_id; }
|
||||
|
||||
int getSetId(int row);
|
||||
int getSetId(QVariant value, Qt::MatchFlags flags = Qt::MatchExactly, int role = Qt::DisplayRole);
|
||||
|
||||
void parseMetaData(int mdt, QJsonDocument * jsonDoc) { itemModel->parseMetaData(mdt, jsonDoc); }
|
||||
|
||||
bool setFlags(int flags) { return filteredItemModel->setFlags(m_id, flags); }
|
||||
|
||||
void setFilterFlags(int flags) { filteredItemModel->setFilterFlags(flags); }
|
||||
void setFilterPattern(const QString & pattern) { filteredItemModel->setFilterPattern(pattern); }
|
||||
|
||||
bool setSubDirectory(const QString path) { return filteredItemModel->setSubDirectory(m_id, path); }
|
||||
bool setCopyFilter(const QString filter) { return filteredItemModel->setCopyFilter(m_id, filter); }
|
||||
|
||||
int count() { return filteredItemModel->rows(); }
|
||||
QStringList list() { return filteredItemModel->list(); }
|
||||
void dumpContentsFiltered() { filteredItemModel->dumpContents(); }
|
||||
|
||||
QString date() { return filteredItemModel->date(m_id); }
|
||||
QString name() { return filteredItemModel->name(m_id); }
|
||||
QString filename() { return filteredItemModel->metaDataValue(m_id, Qt::DisplayRole).toString(); }
|
||||
QString contentType() { return filteredItemModel->metaDataValue(m_id, UpdatesItemModel::IMDR_Content).toString(); }
|
||||
QString subDirectory() { return filteredItemModel->metaDataValue(m_id, UpdatesItemModel::IMDR_SubDirectory).toString(); }
|
||||
QString copyFilter() { return filteredItemModel->metaDataValue(m_id, UpdatesItemModel::IMDR_CopyFilter).toString(); }
|
||||
int flags() { return filteredItemModel->metaDataValue(m_id, UpdatesItemModel::IMDR_Flags).toInt(); }
|
||||
|
||||
const QString urlReleaseAssets(int releaseId) {
|
||||
return QString("%1/%2/assets").arg(urlReleases()).arg(releaseId) % (m_resultsPerPage > -1 ?
|
||||
QString("\?per_page=%1").arg(m_resultsPerPage) : ""); }
|
||||
const QString urlAsset() { return QString("%1/assets/%2").arg(urlReleases()).arg(m_id); }
|
||||
|
||||
private:
|
||||
AssetsItemModel *itemModel;
|
||||
AssetsFilteredItemModel *filteredItemModel;
|
||||
int m_id;
|
||||
};
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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 "reporeleases.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
|
||||
/*
|
||||
ReleasesItemModels
|
||||
*/
|
||||
|
||||
// static
|
||||
const QString ReleasesItemModels::flagsToString(const int flags)
|
||||
{
|
||||
QString str;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int flag = flags & (1 << i);
|
||||
if (flag) {
|
||||
if (!str.isEmpty())
|
||||
str.append(";");
|
||||
str.append(flagToString(flag));
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// static
|
||||
const QString ReleasesItemModels::flagToString(const int val)
|
||||
{
|
||||
const QStringList strl = { "None", "Stable", "Pre-release", "Nightly" };
|
||||
return strl.value(val, CPN_STR_UNKNOWN_ITEM);
|
||||
};
|
||||
|
||||
/*
|
||||
ReleasesRawItemModel
|
||||
*/
|
||||
|
||||
ReleasesRawItemModel::ReleasesRawItemModel() :
|
||||
RepoRawItemModel("Raw Releases"),
|
||||
m_nightlyName("")
|
||||
{
|
||||
setSortRole(RIMR_SortOrder);
|
||||
}
|
||||
|
||||
void ReleasesRawItemModel::parseJsonObject(const QJsonObject & obj)
|
||||
{
|
||||
QStandardItem * item = new QStandardItem();
|
||||
|
||||
int flags = RELFLG_Stable;
|
||||
bool available = true;
|
||||
|
||||
if (!obj.value("name").isUndefined()) {
|
||||
item->setText(obj.value("name").toString());
|
||||
}
|
||||
|
||||
if (!obj.value("id").isUndefined()) {
|
||||
item->setData(obj.value("id").toInt(), RIMR_Id);
|
||||
}
|
||||
|
||||
if (!obj.value("created_at").isUndefined()) {
|
||||
item->setData(QDateTime::fromString(obj.value("created_at").toString(), Qt::ISODate), RIMR_Date);
|
||||
}
|
||||
|
||||
if (!obj.value("prerelease").isUndefined()) {
|
||||
if (obj.value("prerelease").toBool())
|
||||
flags = RELFLG_PreRelease;
|
||||
}
|
||||
|
||||
if (!obj.value("tag_name").isUndefined()) {
|
||||
item->setData(obj.value("tag_name").toString(), RIMR_Tag);
|
||||
if (item->data(RIMR_Tag).toString().toLower() == m_nightlyName)
|
||||
flags = RELFLG_Nightly;
|
||||
}
|
||||
|
||||
if (!obj.value("draft").isUndefined()) {
|
||||
if (obj.value("draft").toBool())
|
||||
available = false;
|
||||
}
|
||||
|
||||
item->setData(available, RIMR_Available);
|
||||
item->setData(flags, RIMR_Flags);
|
||||
|
||||
SemanticVersion sv;
|
||||
|
||||
if (item->data(RIMR_Tag).toString().toLower() == m_nightlyName)
|
||||
sv.fromString("255.255.255");
|
||||
else
|
||||
sv.fromString(item->data(RIMR_Tag).toString());
|
||||
|
||||
if (sv.isValid())
|
||||
item->setData(sv.toInt(), RIMR_SortOrder);
|
||||
else
|
||||
item->setData(item->data(RIMR_Date).toInt(), RIMR_SortOrder);
|
||||
|
||||
appendRow(item);
|
||||
}
|
||||
|
||||
void ReleasesRawItemModel::setNightlyName(const QString name)
|
||||
{
|
||||
m_nightlyName = name.toLower();
|
||||
}
|
||||
|
||||
/*
|
||||
ReleasesFilteredItemModel
|
||||
*/
|
||||
|
||||
ReleasesFilteredItemModel::ReleasesFilteredItemModel(ReleasesRawItemModel * releasesRawItemModel) :
|
||||
RepoFilteredItemModel("Filtered Releases")
|
||||
{
|
||||
setSourceModel(releasesRawItemModel);
|
||||
setSortRole(RIMR_Date);
|
||||
}
|
||||
|
||||
const int ReleasesFilteredItemModel::channelLatestId() const
|
||||
{
|
||||
return rowCount() > 0 ? id(0) : 0;
|
||||
}
|
||||
|
||||
void ReleasesFilteredItemModel::setChannel(const int channel)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
for (int i = 0; i <= channel; i++)
|
||||
flags |= (1 << (i + 1));
|
||||
|
||||
setFilterFlags(flags);
|
||||
}
|
||||
|
||||
const QString ReleasesFilteredItemModel::version(const int id) const
|
||||
{
|
||||
return value(id, RIMR_Tag).toString();
|
||||
}
|
||||
|
||||
/*
|
||||
RepoReleases
|
||||
*/
|
||||
|
||||
RepoReleases::RepoReleases(QObject * parent, UpdateStatus * status, UpdateNetwork * network) :
|
||||
QObject(parent),
|
||||
RepoMetaData(status, network),
|
||||
m_rawItemModel(new ReleasesRawItemModel()),
|
||||
m_filteredItemModel(new ReleasesFilteredItemModel(m_rawItemModel))
|
||||
{
|
||||
setModels(m_rawItemModel, m_filteredItemModel);
|
||||
}
|
||||
|
||||
int RepoReleases::channelLatestId()
|
||||
{
|
||||
return m_filteredItemModel->channelLatestId();
|
||||
}
|
||||
|
||||
void RepoReleases::dumpItemModel(const QString modelName, const QAbstractItemModel * itemModel) const
|
||||
{
|
||||
qDebug() << "Contents of model:" << modelName;
|
||||
|
||||
if (itemModel) {
|
||||
for (int i = 0; i < itemModel->rowCount(); ++i) {
|
||||
qDebug().noquote() << "row:" << i;
|
||||
qDebug().noquote() << " name:" << itemModel->data(itemModel->index(i, 0), Qt::DisplayRole).toString();
|
||||
qDebug().noquote() << " id:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Id).toInt();
|
||||
qDebug().noquote() << " date:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Date).toDateTime();
|
||||
qDebug().noquote() << " version:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Tag).toString();
|
||||
qDebug().noquote() << " flags:" << ReleasesItemModels::flagsToString(itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Flags).toInt());
|
||||
qDebug().noquote() << " avail:" << itemModel->data(itemModel->index(i, 0), RepoItemModelBase::RIMR_Available).toBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RepoReleases::init(const QString & repoPath,const QString & nightly, const int resultsPerPage)
|
||||
{
|
||||
RepoMetaData::init(repoPath, resultsPerPage);
|
||||
m_rawItemModel->setNightlyName(nightly);
|
||||
}
|
||||
|
||||
bool RepoReleases::retrieveMetaDataAll()
|
||||
{
|
||||
return retrieveMetaData(RepoRawItemModel::MDT_Releases, urlReleases());
|
||||
}
|
||||
|
||||
int RepoReleases::setId(const int id)
|
||||
{
|
||||
if (this->id() != id) {
|
||||
RepoMetaData::setId(id);
|
||||
emit idChanged(this->id());
|
||||
}
|
||||
|
||||
return this->id();
|
||||
}
|
||||
|
||||
void RepoReleases::setChannel(const int channel)
|
||||
{
|
||||
m_filteredItemModel->setChannel(channel);
|
||||
getSetId();
|
||||
}
|
||||
|
||||
const QString RepoReleases::version() const
|
||||
{
|
||||
return m_filteredItemModel->version(id());
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 "repodatamodels.h"
|
||||
#include "repometadata.h"
|
||||
|
||||
class ReleasesItemModels
|
||||
{
|
||||
public:
|
||||
explicit ReleasesItemModels() {}
|
||||
virtual ~ReleasesItemModels() {}
|
||||
|
||||
enum ReleaseFlag {
|
||||
RELFLG_None = 0,
|
||||
RELFLG_Stable = 1 << 1,
|
||||
RELFLG_PreRelease = 1 << 2,
|
||||
RELFLG_Nightly = 1 << 3,
|
||||
};
|
||||
|
||||
static const QString flagsToString(const int flags);
|
||||
static const QString flagToString(const int flag);
|
||||
};
|
||||
|
||||
class ReleasesRawItemModel : public RepoRawItemModel, public ReleasesItemModels
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ReleasesRawItemModel();
|
||||
virtual ~ReleasesRawItemModel() {}
|
||||
|
||||
protected:
|
||||
friend class RepoReleases;
|
||||
|
||||
virtual void parseJsonObject(const QJsonObject & obj);
|
||||
|
||||
void setNightlyName(const QString name);
|
||||
|
||||
private:
|
||||
QString m_nightlyName;
|
||||
};
|
||||
|
||||
class ReleasesFilteredItemModel: public RepoFilteredItemModel, public ReleasesItemModels
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ReleasesFilteredItemModel(ReleasesRawItemModel * releasesRawItemModel);
|
||||
virtual ~ReleasesFilteredItemModel() {}
|
||||
|
||||
protected:
|
||||
friend class RepoReleases;
|
||||
|
||||
const int channelLatestId() const;
|
||||
void setChannel(const int channel);
|
||||
const QString version(const int id) const;
|
||||
};
|
||||
|
||||
class RepoReleases : public QObject, public RepoMetaData
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RepoReleases(QObject * parent, UpdateStatus * status, UpdateNetwork * network);
|
||||
virtual ~RepoReleases() {}
|
||||
|
||||
virtual void init(const QString & repoPath, const QString & nightly, const int resultsPerPage);
|
||||
virtual int setId(const int id) override;
|
||||
virtual bool retrieveMetaDataAll();
|
||||
virtual bool retrieveMetaDataOne(const int id) { return false; } // not implemented
|
||||
|
||||
int channelLatestId();
|
||||
void setChannel(const int channel);
|
||||
const QString version() const;
|
||||
|
||||
signals:
|
||||
void idChanged(int id);
|
||||
|
||||
private:
|
||||
ReleasesRawItemModel* const m_rawItemModel;
|
||||
ReleasesFilteredItemModel* const m_filteredItemModel;
|
||||
|
||||
virtual void dumpItemModel(const QString modelName, const QAbstractItemModel * itemModel) const;
|
||||
};
|
||||
@@ -53,14 +53,14 @@
|
||||
#endif
|
||||
|
||||
UpdateCompanion::UpdateCompanion(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
UpdateInterface(parent, CID_Companion, QCoreApplication::translate("UpdateCompanion", "Companion"))
|
||||
{
|
||||
init(CID_Companion, QCoreApplication::translate("UpdateCompanion", "Companion"), QString(GH_REPOS_EDGETX).append("/edgetx"), "nightly");
|
||||
init(QString(GH_API_REPOS_EDGETX).append("/edgetx"), "nightly");
|
||||
}
|
||||
|
||||
void UpdateCompanion::initAssetSettings()
|
||||
void UpdateCompanion::assetSettingsInit()
|
||||
{
|
||||
if (!isValidSettingsIndex())
|
||||
if (!isSettingsIndexValid())
|
||||
return;
|
||||
|
||||
g.component[id()].initAllAssets();
|
||||
@@ -80,24 +80,24 @@ void UpdateCompanion::initAssetSettings()
|
||||
bool UpdateCompanion::asyncInstall()
|
||||
{
|
||||
#ifdef OS_SUPPORTED_INSTALLER
|
||||
//reportProgress(tr("Run application installer: %1").arg(g.runAppInstaller() ? tr("true") : tr("false")), QtDebugMsg);
|
||||
//status()->reportProgress(tr("Run application installer: %1").arg(g.runAppInstaller() ? tr("true") : tr("false")), QtDebugMsg);
|
||||
|
||||
if (!g.runAppInstaller())
|
||||
return true;
|
||||
|
||||
progressMessage(tr("Install"));
|
||||
status()->progressMessage(tr("Install"));
|
||||
|
||||
assets->setFilterFlags(UPDFLG_AsyncInstall);
|
||||
//reportProgress(tr("Asset filter applied: %1 Assets found: %2").arg(updateFlagsToString(UPDFLG_AsyncInstall)).arg(assets->count()), QtDebugMsg);
|
||||
repo()->assets()->setFilterFlags(UPDFLG_AsyncInstall);
|
||||
status()->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_AsyncInstall)).arg(repo()->assets()->count()), QtDebugMsg);
|
||||
|
||||
if (assets->count() != 1) {
|
||||
reportProgress(tr("Expected 1 asset for install but none found"), QtCriticalMsg);
|
||||
if (repo()->assets()->count() != 1) {
|
||||
status()->reportProgress(tr("Expected 1 asset for install but none found"), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
assets->getSetId(0);
|
||||
repo()->assets()->getSetId(0);
|
||||
|
||||
QString installerPath = decompressDir % QString("/A%1/%2").arg(assets->id()).arg(QFileInfo(assets->filename()).completeBaseName());
|
||||
QString installerPath = decompressDir() % QString("/A%1/%2").arg(repo()->assets()->id()).arg(QFileInfo(repo()->assets()->name()).completeBaseName());
|
||||
|
||||
QDirIterator it(installerPath, { OS_INSTALLER_EXTN }, QDir::Files, QDirIterator::Subdirectories);
|
||||
|
||||
@@ -111,14 +111,14 @@ bool UpdateCompanion::asyncInstall()
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
reportProgress(tr("Installer not found in %1 using filter %2").arg(installerPath).arg(OS_INSTALLER_EXTN), QtCriticalMsg);
|
||||
status()->reportProgress(tr("Installer not found in %1 using filter %2").arg(installerPath).arg(OS_INSTALLER_EXTN), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__linux)
|
||||
QFile f(installerPath);
|
||||
if (!f.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner)) {
|
||||
QMessageBox::critical(progress, CPN_STR_APP_NAME, tr("Unable to set file permissions on the AppImage"));
|
||||
QMessageBox::critical(status()->progress(), CPN_STR_APP_NAME, tr("Unable to set file permissions on the AppImage"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -131,24 +131,24 @@ bool UpdateCompanion::asyncInstall()
|
||||
|
||||
if (dest.exists()) {
|
||||
if (!dest.remove()) {
|
||||
QMessageBox::critical(progress, CPN_STR_APP_NAME, tr("Unable to delete file %1").arg(fileName));
|
||||
QMessageBox::critical(status()->progress(), CPN_STR_APP_NAME, tr("Unable to delete file %1").arg(fileName));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!QFile::copy(installerPath, fileName)) {
|
||||
QMessageBox::critical(progress, CPN_STR_APP_NAME, tr("Unable to copy file to %1").arg(fileName));
|
||||
QMessageBox::critical(status()->progress(), CPN_STR_APP_NAME, tr("Unable to copy file to %1").arg(fileName));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QMessageBox::question(progress, CPN_STR_APP_NAME, "Restart Companion?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
if (QMessageBox::question(status()->progress(), CPN_STR_APP_NAME, "Restart Companion?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
QProcess::startDetached(fileName);
|
||||
qApp->exit();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int ret = QMessageBox::question(progress, CPN_STR_APP_NAME, OS_INSTALL_QUESTION, QMessageBox::Yes | QMessageBox::No);
|
||||
int ret = QMessageBox::question(status()->progress(), CPN_STR_APP_NAME, OS_INSTALL_QUESTION, QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (ret == QMessageBox::Yes) {
|
||||
if (QDesktopServices::openUrl(QUrl::fromLocalFile(installerPath)))
|
||||
@@ -160,23 +160,23 @@ bool UpdateCompanion::asyncInstall()
|
||||
return true;
|
||||
|
||||
#else
|
||||
QMessageBox::warning(progress, CPN_STR_APP_NAME, OS_INSTALL_MSG);
|
||||
QMessageBox::warning(status()->progress, CPN_STR_APP_NAME, OS_INSTALL_MSG);
|
||||
return true;
|
||||
#endif // OS_SUPPORTED_INSTALLER
|
||||
}
|
||||
|
||||
const QString UpdateCompanion::currentRelease()
|
||||
const QString UpdateCompanion::releaseCurrent()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
params->currentRelease = QString("EdgeTX \"%1\" %2").arg(CODENAME).arg(VERSION_TAG);
|
||||
params()->releaseCurrent = QString("EdgeTX \"%1\" %2").arg(CODENAME).arg(VERSION_TAG);
|
||||
#else
|
||||
params->currentRelease = QString("EdgeTX v%1.%2.%3-%4").arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_REVISION).arg(VERSION_SUFFIX);
|
||||
params()->releaseCurrent = QString("EdgeTX v%1.%2.%3-%4").arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_REVISION).arg(VERSION_SUFFIX);
|
||||
#endif
|
||||
|
||||
return params->currentRelease;
|
||||
return params()->releaseCurrent;
|
||||
}
|
||||
|
||||
const QString UpdateCompanion::currentVersion()
|
||||
const QString UpdateCompanion::versionCurrent()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
return VERSION_TAG;
|
||||
@@ -185,10 +185,10 @@ const QString UpdateCompanion::currentVersion()
|
||||
#endif
|
||||
}
|
||||
|
||||
const bool UpdateCompanion::isLatestRelease()
|
||||
const bool UpdateCompanion::isReleaseLatest()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
return UpdateInterface::isLatestRelease();
|
||||
return UpdateInterface::isReleaseLatest();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -32,12 +32,12 @@ class UpdateCompanion : public UpdateInterface
|
||||
explicit UpdateCompanion(QWidget * parent);
|
||||
virtual ~UpdateCompanion() {}
|
||||
|
||||
protected:
|
||||
virtual void initAssetSettings() override;
|
||||
|
||||
virtual bool asyncInstall() override;
|
||||
virtual const QString currentRelease() override;
|
||||
virtual const QString currentVersion() override;
|
||||
virtual const bool isLatestRelease() override;
|
||||
virtual const QString releaseCurrent() override;
|
||||
virtual const QString versionCurrent() override;
|
||||
virtual const bool isReleaseLatest() override;
|
||||
virtual const bool isUpdateAvailable() override;
|
||||
|
||||
protected:
|
||||
virtual bool asyncInstall() override;
|
||||
virtual void assetSettingsInit() override;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 "updatefactories.h"
|
||||
#include "updatefirmware.h"
|
||||
#include "updatecompanion.h"
|
||||
#include "updatesdcard.h"
|
||||
#include "updatesounds.h"
|
||||
#include "updatethemes.h"
|
||||
#include "updatemultiprotocol.h"
|
||||
|
||||
UpdateFactories::UpdateFactories(QWidget * parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
registerUpdateFactories();
|
||||
}
|
||||
|
||||
UpdateFactories::~UpdateFactories()
|
||||
{
|
||||
unregisterUpdateFactories();
|
||||
}
|
||||
|
||||
UpdateInterface* const UpdateFactories::instance(const int id)
|
||||
{
|
||||
foreach (UpdateFactoryInterface * factory, registeredUpdateFactories) {
|
||||
if (id == factory->id())
|
||||
return factory->instance();
|
||||
}
|
||||
qDebug() << "Critical error - Interface not found for id:" << id;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool UpdateFactories::isUpdateAvailable(QMap<QString, int> & list)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
list.clear();
|
||||
|
||||
foreach (UpdateFactoryInterface * factory, registeredUpdateFactories) {
|
||||
if (factory->instance()->isUpdateable() && factory->instance()->isUpdateAvailable()) {
|
||||
list.insert(factory->name(), factory->id());
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UpdateFactories::registerUpdateFactory(UpdateFactoryInterface * factory)
|
||||
{
|
||||
foreach (UpdateFactoryInterface * registeredFactory, registeredUpdateFactories) {
|
||||
if (registeredFactory->id() == factory->id()) {
|
||||
qDebug() << "Duplicate factory - id:" << factory->id() << "name:" << factory->name();
|
||||
return;
|
||||
}
|
||||
}
|
||||
registeredUpdateFactories.append(factory);
|
||||
qDebug() << "Registered update factory:" << factory->name();
|
||||
}
|
||||
|
||||
void UpdateFactories::registerUpdateFactories()
|
||||
{
|
||||
// Note: register in logical updating sequence
|
||||
// SDCard should be first as it may clean up/erase commmon destination directory
|
||||
registerUpdateFactory(new UpdateFactory<UpdateSDCard>(this));
|
||||
registerUpdateFactory(new UpdateFactory<UpdateFirmware>(this));
|
||||
registerUpdateFactory(new UpdateFactory<UpdateSounds>(this));
|
||||
registerUpdateFactory(new UpdateFactory<UpdateThemes>(this));
|
||||
registerUpdateFactory(new UpdateFactory<UpdateMultiProtocol>(this));
|
||||
|
||||
// Note: Companion must be last as its install requires the app to be closed and thus would interrupt the update loop
|
||||
registerUpdateFactory(new UpdateFactory<UpdateCompanion>(this));
|
||||
}
|
||||
|
||||
void UpdateFactories::resetAllEnvironments()
|
||||
{
|
||||
foreach (UpdateFactoryInterface * factory, registeredUpdateFactories) {
|
||||
factory->instance()->resetEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
const QMap<QString, int> UpdateFactories::sortedComponentsList(bool updateableOnly)
|
||||
{
|
||||
QMap<QString, int> map;
|
||||
|
||||
foreach (UpdateFactoryInterface * factory, registeredUpdateFactories) {
|
||||
if (updateableOnly && !factory->instance()->isUpdateable())
|
||||
continue;
|
||||
map.insert(factory->name(), factory->id());
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
bool UpdateFactories::updateAll(ProgressWidget * progress)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
foreach (UpdateFactoryInterface * factory, registeredUpdateFactories) {
|
||||
ret = factory->instance()->update(progress);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UpdateFactories::unregisterUpdateFactories()
|
||||
{
|
||||
foreach (UpdateFactoryInterface * factory, registeredUpdateFactories)
|
||||
delete factory;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 "updateinterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class UpdateFactoryInterface
|
||||
{
|
||||
public:
|
||||
explicit UpdateFactoryInterface() {}
|
||||
virtual ~UpdateFactoryInterface() {}
|
||||
|
||||
virtual const int id() = 0;
|
||||
virtual UpdateInterface* const instance() = 0;
|
||||
virtual const QString name() = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class UpdateFactory : public UpdateFactoryInterface
|
||||
{
|
||||
public:
|
||||
explicit UpdateFactory(QWidget * parent) :
|
||||
UpdateFactoryInterface(),
|
||||
m_instance(new T(parent)) {}
|
||||
|
||||
virtual ~UpdateFactory() {}
|
||||
|
||||
virtual const int id() { return m_instance->id(); }
|
||||
virtual UpdateInterface* const instance() { return m_instance; }
|
||||
virtual const QString name() { return m_instance->name(); }
|
||||
|
||||
private:
|
||||
UpdateInterface* const m_instance;
|
||||
};
|
||||
|
||||
class UpdateFactories : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateFactories(QWidget * parent = nullptr);
|
||||
virtual ~UpdateFactories();
|
||||
|
||||
UpdateInterface* const instance(const int id);
|
||||
const bool isUpdateAvailable(QMap<QString, int> & names);
|
||||
void registerUpdateFactories();
|
||||
void registerUpdateFactory(UpdateFactoryInterface * factory);
|
||||
void resetAllEnvironments();
|
||||
const QMap<QString, int> sortedComponentsList(bool updateableOnly = false);
|
||||
void unregisterUpdateFactories();
|
||||
bool updateAll(ProgressWidget * progress = nullptr);
|
||||
|
||||
private:
|
||||
QVector<UpdateFactoryInterface *> registeredUpdateFactories;
|
||||
};
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
#include "flashfirmwaredialog.h"
|
||||
|
||||
UpdateFirmware::UpdateFirmware(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
UpdateInterface(parent, CID_Firmware, tr("Firmware"))
|
||||
{
|
||||
init(CID_Firmware, tr("Firmware"), QString(GH_REPOS_EDGETX).append("/edgetx"), "nightly");
|
||||
init(QString(GH_API_REPOS_EDGETX).append("/edgetx"), "nightly");
|
||||
}
|
||||
|
||||
void UpdateFirmware::initAssetSettings()
|
||||
void UpdateFirmware::assetSettingsInit()
|
||||
{
|
||||
if (!isValidSettingsIndex())
|
||||
if (!isSettingsIndexValid())
|
||||
return;
|
||||
|
||||
g.component[id()].initAllAssets();
|
||||
@@ -44,7 +44,7 @@ void UpdateFirmware::initAssetSettings()
|
||||
cad.filter("edgetx-firmware");
|
||||
cad.maxExpected(1);
|
||||
cad.destSubDir("FIRMWARE");
|
||||
cad.copyFilterType(UpdateParameters::UFT_Expression);
|
||||
cad.copyFilterType(UpdateParameters::UFT_Pattern);
|
||||
cad.copyFilter("^%FWFLAVOUR%-.*\\.bin$");
|
||||
|
||||
qDebug() << "Asset settings initialised";
|
||||
@@ -52,32 +52,32 @@ void UpdateFirmware::initAssetSettings()
|
||||
|
||||
bool UpdateFirmware::asyncInstall()
|
||||
{
|
||||
//reportProgress(tr("Write firmware to radio: %1").arg(g.currentProfile().burnFirmware() ? tr("true") : tr("false")), QtDebugMsg);
|
||||
//status->reportProgress(tr("Write firmware to radio: %1").arg(g.currentProfile().burnFirmware() ? tr("true") : tr("false")), QtDebugMsg);
|
||||
|
||||
if (!g.currentProfile().burnFirmware())
|
||||
return true;
|
||||
|
||||
progressMessage(tr("Install"));
|
||||
status()->progressMessage(tr("Install"));
|
||||
|
||||
assets->setFilterFlags(UPDFLG_AsyncInstall);
|
||||
//reportProgress(tr("Asset filter applied: %1 Assets found: %2").arg(updateFlagsToString(UPDFLG_AsyncInstall)).arg(assets->count()), QtDebugMsg);
|
||||
repo()->assets()->setFilterFlags(UPDFLG_AsyncInstall);
|
||||
//status->reportProgress(tr("Asset filter applied: %1 Assets found: %2").arg(updateFlagsToString(UPDFLG_AsyncInstall)).arg(assets->count()), QtDebugMsg);
|
||||
|
||||
if (assets->count() < 1)
|
||||
if (repo()->assets()->count() < 1)
|
||||
return true;
|
||||
|
||||
if (assets->count() != params->assets.at(0).maxExpected) {
|
||||
reportProgress(tr("Expected %1 asset for install but %2 found").arg(params->assets.at(0).maxExpected).arg(assets->count()), QtCriticalMsg);
|
||||
if (repo()->assets()->count() != params()->assets.at(0).maxExpected) {
|
||||
status()->reportProgress(tr("Expected %1 asset for install but %2 found").arg(params()->assets.at(0).maxExpected).arg(repo()->assets()->count()), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString destPath = updateDir;
|
||||
QString destPath = updateDir();
|
||||
|
||||
if (!assets->subDirectory().isEmpty())
|
||||
destPath.append("/" % assets->subDirectory());
|
||||
if (!repo()->assets()->subDirectory().isEmpty())
|
||||
destPath.append("/" % repo()->assets()->subDirectory());
|
||||
|
||||
const UpdateParameters::AssetParams &ap = params->assets.at(0);
|
||||
const UpdateParameters::AssetParams &ap = params()->assets.at(0);
|
||||
|
||||
QString pattern(params->buildFilterPattern(ap.copyFilterType, ap.copyFilter));
|
||||
QString pattern(params()->buildFilterPattern(ap.copyFilterType, ap.copyFilter));
|
||||
QRegularExpression filter(pattern, QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
QDirIterator it(destPath);
|
||||
@@ -97,13 +97,13 @@ bool UpdateFirmware::asyncInstall()
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
reportProgress(tr("Firmware not found in %1 using filter %2").arg(destPath).arg(filter.pattern()), QtCriticalMsg);
|
||||
status()->reportProgress(tr("Firmware not found in %1 using filter %2").arg(destPath).arg(filter.pattern()), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
g.currentProfile().fwName(destPath);
|
||||
|
||||
int ret = QMessageBox::question(progress, CPN_STR_APP_NAME, tr("Write the updated firmware to the radio now ?"), QMessageBox::Yes | QMessageBox::No);
|
||||
int ret = QMessageBox::question(status()->progress(), CPN_STR_APP_NAME, tr("Write the updated firmware to the radio now ?"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::Yes) {
|
||||
FlashFirmwareDialog *dlg = new FlashFirmwareDialog(this);
|
||||
dlg->exec();
|
||||
|
||||
@@ -33,7 +33,6 @@ class UpdateFirmware : public UpdateInterface
|
||||
virtual ~UpdateFirmware() {}
|
||||
|
||||
protected:
|
||||
virtual void initAssetSettings() override;
|
||||
|
||||
virtual bool asyncInstall() override;
|
||||
virtual void assetSettingsInit() override;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,65 +21,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "repomodels.h"
|
||||
#include "constants.h"
|
||||
#include "progresswidget.h"
|
||||
#include "appdata.h"
|
||||
#include "updatestatus.h"
|
||||
#include "updatenetwork.h"
|
||||
#include "repo.h"
|
||||
#include "updateparameters.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
class UpdateParameters : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum UpdateFilterType {
|
||||
UFT_None,
|
||||
UFT_Exact,
|
||||
UFT_Startswith,
|
||||
UFT_Endswith,
|
||||
UFT_Contains,
|
||||
UFT_Expression,
|
||||
};
|
||||
|
||||
static QStringList updateFilterTypeList();
|
||||
|
||||
static QString updateFilterTypeToString(UpdateFilterType uft);
|
||||
|
||||
struct AssetParams {
|
||||
int processes;
|
||||
int flags;
|
||||
UpdateFilterType filterType;
|
||||
QString filter;
|
||||
int maxExpected;
|
||||
QString destSubDir;
|
||||
UpdateFilterType copyFilterType;
|
||||
QString copyFilter;
|
||||
};
|
||||
|
||||
int flags;
|
||||
int logLevel;
|
||||
QString fwFlavour;
|
||||
QString language;
|
||||
int releaseChannel;
|
||||
QString currentRelease;
|
||||
QString updateRelease;
|
||||
QString downloadDir;
|
||||
bool decompressDirUseDwnld;
|
||||
QString decompressDir;
|
||||
QString sdDir;
|
||||
bool updateDirUseSD;
|
||||
QString updateDir;
|
||||
QVector<AssetParams> assets;
|
||||
|
||||
UpdateParameters(QObject * parent);
|
||||
virtual ~UpdateParameters() {}
|
||||
|
||||
AssetParams & addAsset();
|
||||
QString buildFilterPattern(const UpdateFilterType filterType, const QString & filter);
|
||||
};
|
||||
#include <QWidget>
|
||||
|
||||
class UpdateInterface : public QWidget
|
||||
{
|
||||
@@ -87,13 +37,19 @@ class UpdateInterface : public QWidget
|
||||
|
||||
public:
|
||||
|
||||
enum DownloadDataType {
|
||||
DDT_Binary,
|
||||
DDT_Content,
|
||||
DDT_SaveToFile,
|
||||
DDT_MetaData,
|
||||
// The CID is used as a key to the application settings therefore
|
||||
// ids must be explicit so no renumbering if components removed
|
||||
// new components must be added to the end of the enum
|
||||
enum ComponentIdentity {
|
||||
CID_Unknown = -1,
|
||||
CID_SDCard = 0,
|
||||
CID_Firmware = 1,
|
||||
CID_Sounds = 2,
|
||||
CID_Themes = 3,
|
||||
CID_MultiProtocol = 4,
|
||||
CID_Companion = 5,
|
||||
};
|
||||
Q_ENUM(DownloadDataType)
|
||||
Q_ENUM(ComponentIdentity)
|
||||
|
||||
enum UpdateFlags {
|
||||
UPDFLG_None = 0,
|
||||
@@ -114,212 +70,81 @@ class UpdateInterface : public QWidget
|
||||
};
|
||||
Q_ENUM(UpdateFlags)
|
||||
|
||||
// The CID is used as a key to the application settings therefore
|
||||
// ids must be explicit so no renumbering if components removed
|
||||
// new components must be added to the end of the enum
|
||||
enum ComponentIdentity {
|
||||
CID_Unknown = -1,
|
||||
CID_SDCard = 0,
|
||||
CID_Firmware = 1,
|
||||
CID_Sounds = 2,
|
||||
CID_Themes = 3,
|
||||
CID_MultiProtocol = 4,
|
||||
CID_Companion = 5,
|
||||
};
|
||||
Q_ENUM(ComponentIdentity)
|
||||
|
||||
explicit UpdateInterface(QWidget * parent);
|
||||
explicit UpdateInterface(QWidget * parent, ComponentIdentity id, QString name);
|
||||
virtual ~UpdateInterface();
|
||||
|
||||
const int id() const { return (int)m_id; }
|
||||
const QString name() const { return m_name; }
|
||||
virtual void assetSettingsSave();
|
||||
virtual const bool isReleaseLatest();
|
||||
virtual const bool isUpdateAvailable();
|
||||
virtual const bool isVersionLatest(const QString & current, const QString & latest);
|
||||
virtual const QString releaseCurrent();
|
||||
virtual const QString releaseLatest();
|
||||
virtual const QString releaseUpdate();
|
||||
virtual bool update(ProgressWidget * progress = nullptr);
|
||||
virtual const QString versionCurrent();
|
||||
|
||||
const int id() const;
|
||||
const bool isUpdateable() const;
|
||||
const QString name() const;
|
||||
UpdateParameters* const params() const;
|
||||
void releaseClear();
|
||||
const QStringList releaseList();
|
||||
void resetEnvironment();
|
||||
void setReleaseChannel(const int channel);
|
||||
void setRunUpdate();
|
||||
|
||||
protected:
|
||||
friend class UpdateFactories;
|
||||
|
||||
ReleasesMetaData *releases;
|
||||
AssetsMetaData *assets;
|
||||
UpdateParameters *params;
|
||||
ProgressWidget *progress;
|
||||
|
||||
QString downloadDir;
|
||||
QString decompressDir;
|
||||
QString updateDir;
|
||||
|
||||
virtual bool update(ProgressWidget * progress = nullptr);
|
||||
|
||||
virtual void initAssetSettings() = 0;
|
||||
virtual void loadAssetSettings();
|
||||
virtual void saveAssetSettings();
|
||||
|
||||
virtual bool preparation();
|
||||
virtual bool flagAssets();
|
||||
virtual bool download();
|
||||
virtual bool decompress();
|
||||
virtual bool copyToDestination();
|
||||
virtual bool copyAsset();
|
||||
virtual bool housekeeping();
|
||||
virtual void assetSettingsInit() = 0;
|
||||
virtual void assetSettingsLoad();
|
||||
virtual bool asyncInstall();
|
||||
virtual bool copyAsset();
|
||||
virtual bool copyToDestination();
|
||||
virtual bool decompress();
|
||||
virtual bool download();
|
||||
virtual bool flagAssets();
|
||||
virtual bool housekeeping();
|
||||
virtual bool preparation();
|
||||
|
||||
virtual const bool isUpdateAvailable();
|
||||
virtual const QString currentVersion();
|
||||
virtual const QString currentRelease();
|
||||
virtual const QString updateRelease();
|
||||
virtual const bool isLatestRelease();
|
||||
virtual const bool isLatestVersion(const QString & current, const QString & latest);
|
||||
virtual QString latestRelease();
|
||||
|
||||
void clearRelease();
|
||||
const QStringList getReleases();
|
||||
|
||||
void init(ComponentIdentity id, QString name, QString repo, QString nightly = "", int resultsPerPage = -1);
|
||||
|
||||
void setId(ComponentIdentity id) { m_id = id; }
|
||||
void setName(QString name) { m_name = name; }
|
||||
|
||||
void setReleaseChannel(int channel);
|
||||
void setReleaseId(QString val);
|
||||
|
||||
void setParamFolders();
|
||||
UpdateParameters * getParams() { return params; }
|
||||
void resetEnvironment();
|
||||
void setRunUpdate() { params->flags |= UPDFLG_Update; }
|
||||
bool isUpdateable();
|
||||
|
||||
bool repoReleasesMetaData();
|
||||
bool repoReleaseAssetsMetaData();
|
||||
|
||||
bool downloadReleasesMetaData();
|
||||
bool downloadReleaseLatestMetaData();
|
||||
bool downloadReleaseMetaData(const int releaseId);
|
||||
|
||||
bool getReleaseJsonAsset(const QString assetName, QJsonDocument * json);
|
||||
bool downloadReleaseAssetsMetaData(const int releaseId);
|
||||
bool downloadAssetMetaData(const int assetId);
|
||||
bool getSetAssets(const UpdateParameters::AssetParams & ap);
|
||||
bool downloadAsset(int row);
|
||||
bool downloadFlaggedAssets();
|
||||
bool decompressAsset(int row);
|
||||
bool decompressFlaggedAssets();
|
||||
bool copyFiles();
|
||||
bool copyFlaggedAssets();
|
||||
bool copyStructure();
|
||||
bool copyFiles();
|
||||
|
||||
bool saveReleaseSettings();
|
||||
|
||||
bool downloadAssetToBuffer(const int assetId);
|
||||
bool downloadTextFileToBuffer(const QString & path);
|
||||
void downloadFileToBuffer(const QString & url);
|
||||
bool convertDownloadToJson(QJsonDocument * json);
|
||||
bool decompressArchive(const QString & archivePath, const QString & destPath);
|
||||
QByteArray * getDownloadBuffer() { return buffer; }
|
||||
|
||||
bool getRepoJsonFile(const QString filename, QJsonDocument * json);
|
||||
|
||||
void reportProgress(const QString & text, const int type = QtInfoMsg);
|
||||
void progressMessage(const QString & text);
|
||||
void criticalMsg(const QString & msg);
|
||||
static QString downloadDataTypeToString(DownloadDataType val);
|
||||
static QString updateFlagsToString(UpdateFlags val);
|
||||
void setFlavourLanguage();
|
||||
bool isValidSettingsIndex() { return m_id > -1 && m_id < MAX_COMPONENTS; }
|
||||
|
||||
private slots:
|
||||
void onDownloadFinished(QNetworkReply * reply, DownloadDataType ddt, int subtype);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request;
|
||||
QNetworkReply *reply;
|
||||
QByteArray *buffer;
|
||||
QFile *file;
|
||||
QUrl url;
|
||||
int m_id;
|
||||
QString m_name;
|
||||
|
||||
bool downloadSuccess;
|
||||
bool decompressAsset(int row);
|
||||
const QString decompressDir() const;
|
||||
bool decompressFlaggedAssets();
|
||||
const QString downloadDir() const;
|
||||
bool downloadFlaggedAssets();
|
||||
void init(QString repo, QString nightly = "", int resultsPerPage = -1);
|
||||
const bool isSettingsIndexValid() const;
|
||||
UpdateNetwork* const network() const;
|
||||
Repo* const repo() const;
|
||||
bool retrieveAssetsJsonFile(const QString & assetName, QJsonDocument * json);
|
||||
bool retrieveRepoJsonFile(const QString & filename, QJsonDocument * json);
|
||||
bool setFilteredAssets(const UpdateParameters::AssetParams & ap);
|
||||
void setFirmwareFlavour();
|
||||
void setLanguage();
|
||||
void setParamFolders();
|
||||
void setReleaseId(QString name);
|
||||
UpdateStatus* const status() const;
|
||||
const QString updateDir() const;
|
||||
|
||||
static QStringList versionToStringList(QString version);
|
||||
static const QString updateFlagsToString(const int flags);
|
||||
static const QString updateFlagToString(const int flag);
|
||||
|
||||
void initAppSettings();
|
||||
bool setRunFolders();
|
||||
private:
|
||||
const ComponentIdentity m_id;
|
||||
const QString m_name;
|
||||
UpdateParameters* const m_params;
|
||||
UpdateStatus* const m_status;
|
||||
UpdateNetwork* const m_network;
|
||||
Repo* const m_repo;
|
||||
QString m_downloadDir;
|
||||
QString m_decompressDir;
|
||||
QString m_updateDir;
|
||||
|
||||
void appSettingsInit();
|
||||
bool checkCreateDirectory(const QString & dirSetting, const UpdateFlags flag);
|
||||
|
||||
void downloadMetaData(const MetaDataType mdt, const QString & url);
|
||||
void download(const DownloadDataType type, const int subtype, const QString & urlStr, const char * header, const QString & filePath);
|
||||
void downloadBinaryToFile(const QString & url, const QString & filename);
|
||||
|
||||
void parseMetaData(int mdt);
|
||||
};
|
||||
|
||||
class UpdateFactoryInterface
|
||||
{
|
||||
public:
|
||||
explicit UpdateFactoryInterface() {}
|
||||
virtual ~UpdateFactoryInterface() {}
|
||||
virtual UpdateInterface * instance() = 0;
|
||||
virtual const QString name() = 0;
|
||||
virtual const int id() = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class UpdateFactory : public UpdateFactoryInterface
|
||||
{
|
||||
public:
|
||||
explicit UpdateFactory(QWidget * parent) :
|
||||
UpdateFactoryInterface(),
|
||||
m_instance(new T(parent)) {}
|
||||
|
||||
virtual ~UpdateFactory() {}
|
||||
|
||||
virtual UpdateInterface * instance() { return m_instance; }
|
||||
virtual const QString name() { return m_instance->name(); }
|
||||
virtual const int id() { return m_instance->id(); }
|
||||
|
||||
private:
|
||||
UpdateInterface *m_instance;
|
||||
};
|
||||
|
||||
class UpdateFactories : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateFactories(QWidget * parent = nullptr);
|
||||
virtual ~UpdateFactories();
|
||||
|
||||
const QString name(const int id);
|
||||
|
||||
void registerUpdateFactory(UpdateFactoryInterface * factory);
|
||||
void registerUpdateFactories();
|
||||
void unregisterUpdateFactories();
|
||||
|
||||
void saveAssetSettings(const int id);
|
||||
|
||||
UpdateParameters * const getParams(const int id);
|
||||
void resetEnvironment(const int id);
|
||||
void resetAllEnvironments();
|
||||
void setRunUpdate(const int id);
|
||||
const QMap<QString, int> sortedComponentsList(bool updateableOnly = false);
|
||||
|
||||
void clearRelease(const int id);
|
||||
void setReleaseChannel(const int id, int channel);
|
||||
void setReleaseId(const int id, QString val);
|
||||
const QString currentRelease(const int id);
|
||||
const QString updateRelease(const int id);
|
||||
const bool isLatestRelease(const int id);
|
||||
const QString latestRelease(const int id);
|
||||
const QStringList releases(const int id);
|
||||
bool getReleaseJsonAsset(const int id, const QString assetName, QJsonDocument * json);
|
||||
|
||||
bool getRepoJsonFile(const int id, const QString filename, QJsonDocument * json);
|
||||
|
||||
bool update(const int id, ProgressWidget * progress = nullptr);
|
||||
bool updateAll(ProgressWidget * progress = nullptr);
|
||||
const bool isUpdateAvailable(QMap<QString, int> & names);
|
||||
|
||||
private:
|
||||
QVector<UpdateFactoryInterface *> registeredUpdateFactories;
|
||||
|
||||
UpdateInterface * getInstance(const int id);
|
||||
bool decompressArchive(const QString & archivePath, const QString & destPath);
|
||||
bool releaseSettingsSave();
|
||||
bool setRunFolders();
|
||||
};
|
||||
|
||||
@@ -22,15 +22,15 @@
|
||||
#include "updatemultiprotocol.h"
|
||||
|
||||
UpdateMultiProtocol::UpdateMultiProtocol(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
UpdateInterface(parent, CID_MultiProtocol, tr("Multiprotocol"))
|
||||
{
|
||||
// GitHub REST API default ResultsPerPage = 30
|
||||
init(CID_MultiProtocol, tr("Multiprotocol"), QString(GITHUB_API_REPOS).append("/pascallanger/DIY-Multiprotocol-TX-Module"), "", 50);
|
||||
init(QString(GH_API_REPOS).append("/pascallanger/DIY-Multiprotocol-TX-Module"), "", 50);
|
||||
}
|
||||
|
||||
void UpdateMultiProtocol::initAssetSettings()
|
||||
void UpdateMultiProtocol::assetSettingsInit()
|
||||
{
|
||||
if (!isValidSettingsIndex())
|
||||
if (!isSettingsIndexValid())
|
||||
return;
|
||||
|
||||
g.component[id()].initAllAssets();
|
||||
@@ -49,7 +49,7 @@ void UpdateMultiProtocol::initAssetSettings()
|
||||
cad.desc("binaries");
|
||||
cad.processes(UPDFLG_Common_Asset &~ UPDFLG_Decompress);
|
||||
cad.flags(cad.processes() | UPDFLG_CopyFiles);
|
||||
cad.filterType(UpdateParameters::UFT_Expression);
|
||||
cad.filterType(UpdateParameters::UFT_Pattern);
|
||||
cad.filter("^mm-stm-serial-.*\\.bin$");
|
||||
cad.destSubDir("FIRMWARE");
|
||||
}
|
||||
|
||||
@@ -35,6 +35,5 @@ class UpdateMultiProtocol : public UpdateInterface
|
||||
virtual ~UpdateMultiProtocol() {}
|
||||
|
||||
protected:
|
||||
virtual void initAssetSettings() override;
|
||||
|
||||
virtual void assetSettingsInit() override;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 "updatenetwork.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QtNetwork/QNetworkProxyFactory>
|
||||
|
||||
constexpr char GH_API_VERSION[] {"2022-11-28"};
|
||||
constexpr char GH_ACCEPT_HEADER_CONTENT[] {"application/octet-stream"};
|
||||
constexpr char GH_ACCEPT_HEADER_METADATA[] {"application/vnd.github+json"};
|
||||
constexpr char GH_ACCEPT_HEADER_RAW[] {"application/vnd.github.raw"};
|
||||
|
||||
UpdateNetwork::UpdateNetwork(QObject * parent, UpdateStatus * status) :
|
||||
QObject(parent),
|
||||
m_status(status),
|
||||
m_reply(nullptr),
|
||||
m_buffer(new QByteArray()),
|
||||
m_file(nullptr)
|
||||
{
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
}
|
||||
|
||||
UpdateNetwork::~UpdateNetwork()
|
||||
{
|
||||
delete m_buffer;
|
||||
if (m_reply)
|
||||
delete m_reply;
|
||||
if (m_file)
|
||||
delete m_file;
|
||||
}
|
||||
|
||||
// static
|
||||
QString UpdateNetwork::downloadDataTypeToString(const DownloadDataType val)
|
||||
{
|
||||
switch ((int)val) {
|
||||
case DDT_Binary:
|
||||
return "Binary";
|
||||
case DDT_Content:
|
||||
return "Content";
|
||||
case DDT_MetaData:
|
||||
return "Meta Data";
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateNetwork::downloadMetaData(const QString & url, QJsonDocument * json)
|
||||
{
|
||||
downloadToBuffer(DDT_MetaData, url);
|
||||
if (m_success)
|
||||
convertBufferToJson(json);
|
||||
}
|
||||
|
||||
void UpdateNetwork::downloadJson(const QString & url, QJsonDocument * json)
|
||||
{
|
||||
downloadToBuffer(DDT_Content, url);
|
||||
if (m_success)
|
||||
convertBufferToJson(json);
|
||||
}
|
||||
|
||||
void UpdateNetwork::downloadToBuffer(const DownloadDataType type, const QString & url)
|
||||
{
|
||||
m_success = false;
|
||||
download(type, url, type == DDT_MetaData ? GH_ACCEPT_HEADER_METADATA : GH_ACCEPT_HEADER_CONTENT, QString());
|
||||
}
|
||||
|
||||
void UpdateNetwork::downloadToFile(const QString & url, const QString & filePath)
|
||||
{
|
||||
m_success = false;
|
||||
|
||||
QFileInfo fi(filePath);
|
||||
|
||||
m_status->progressMessage(tr("Downloading: %1").arg(fi.fileName()));
|
||||
m_status->reportProgress(tr("Download: %1").arg(fi.fileName()));
|
||||
|
||||
if (fi.exists()) {
|
||||
m_status->reportProgress(tr("File exists: %1").arg(fi.fileName()), QtDebugMsg);
|
||||
if (m_status) {
|
||||
int reply = QMessageBox::question(m_status->progress(), CPN_STR_APP_NAME, tr("File %1 exists. Download again?").arg(fi.fileName()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::No);
|
||||
if (reply == QMessageBox::Cancel) {
|
||||
return;
|
||||
}
|
||||
else if (reply == QMessageBox::No) {
|
||||
m_success = true;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!QDir().mkpath(fi.path())) {
|
||||
m_status->reportProgress(tr("Failed to create directory %1!").arg(fi.path()), QtCriticalMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
download(DDT_SaveToFile, url, GH_ACCEPT_HEADER_CONTENT, fi.absoluteFilePath());
|
||||
}
|
||||
|
||||
void UpdateNetwork::download(const DownloadDataType type, const QString & urlStr, const char * header, const QString & filePath)
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_status->setMaximum(100);
|
||||
|
||||
m_buffer->clear();
|
||||
m_success = false;
|
||||
|
||||
if (type == DDT_SaveToFile) {
|
||||
m_file = new QFile(filePath);
|
||||
if (!m_file->open(QIODevice::WriteOnly)) {
|
||||
m_status->criticalMsg(tr("Unable to open the download file %1 for writing. Error: %2").arg(filePath).arg(m_file->errorString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_file = nullptr;
|
||||
|
||||
m_url.setUrl(urlStr);
|
||||
|
||||
if (!m_url.isValid()) {
|
||||
m_status->criticalMsg(tr("Invalid URL: %1").arg(urlStr));
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_status->reportProgress(tr("URL: %1").arg(urlStr), QtDebugMsg);
|
||||
|
||||
m_request.setUrl(m_url);
|
||||
m_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
|
||||
m_request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
|
||||
m_request.setRawHeader(QByteArray("X-GitHub-Api-Version"), GH_API_VERSION);
|
||||
m_request.setRawHeader(QByteArray("Accept"), QByteArray(header));
|
||||
|
||||
m_reply = m_manager.get(m_request);
|
||||
|
||||
connect(m_reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), [=] (QNetworkReply::NetworkError code) {
|
||||
// leave it to the finished slot to deal with error condition
|
||||
m_status->criticalMsg(tr("Network error has occurred. Error code: %1").arg(code));
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::sslErrors, [=]() {
|
||||
m_status->reportProgress(tr("Ssl library version: %1").arg(QSslSocket::sslLibraryVersionString()), QtDebugMsg);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::readyRead, [=]() {
|
||||
if (type == DDT_SaveToFile) {
|
||||
m_file->write(m_reply->readAll());
|
||||
}
|
||||
else {
|
||||
const QByteArray qba = m_reply->readAll();
|
||||
m_buffer->append(qba);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::finished, [&]() {
|
||||
onDownloadFinished(m_reply, type);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::downloadProgress, [=](const qint64 bytesRead, const qint64 totalBytes) {
|
||||
m_status->setMaximum(totalBytes);
|
||||
m_status->setValue(bytesRead);
|
||||
});
|
||||
|
||||
while (!m_reply->isFinished()) {
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray * UpdateNetwork::getDownloadBuffer()
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
const bool UpdateNetwork::isSuccess()
|
||||
{
|
||||
return m_success;
|
||||
}
|
||||
|
||||
void UpdateNetwork::onDownloadFinished(QNetworkReply * reply, DownloadDataType type)
|
||||
{
|
||||
m_status->setValue(m_status->maximum());
|
||||
|
||||
if (type == DDT_SaveToFile) {
|
||||
m_file->flush();
|
||||
m_file->close();
|
||||
}
|
||||
|
||||
if (m_reply->error()) {
|
||||
m_success = false;
|
||||
m_status->criticalMsg(tr("Unable to download %1. Error:%2\n%3").arg(downloadDataTypeToString(type)).arg(m_reply->error()).arg(m_reply->errorString()));
|
||||
|
||||
if (type == DDT_SaveToFile)
|
||||
m_file->remove();
|
||||
}
|
||||
else
|
||||
m_success = true;
|
||||
|
||||
if (type == DDT_SaveToFile) {
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateNetwork::convertBufferToJson(QJsonDocument * json)
|
||||
{
|
||||
m_success = false;
|
||||
QJsonParseError res;
|
||||
|
||||
*json = QJsonDocument::fromJson(*m_buffer, &res);
|
||||
|
||||
if (res.error || json->isNull()) {
|
||||
m_status->criticalMsg(tr("Unable to convert downloaded metadata to json. Error:%1\n%2").arg(res.error).arg(res.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
m_success = true;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 "updatestatus.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
|
||||
class UpdateNetwork : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum DownloadDataType {
|
||||
DDT_Binary,
|
||||
DDT_Content,
|
||||
DDT_SaveToFile,
|
||||
DDT_MetaData,
|
||||
};
|
||||
Q_ENUM(DownloadDataType)
|
||||
|
||||
explicit UpdateNetwork(QObject * parent, UpdateStatus * status);
|
||||
virtual ~UpdateNetwork();
|
||||
|
||||
void convertBufferToJson(QJsonDocument * json);
|
||||
void downloadMetaData(const QString & url, QJsonDocument * json);
|
||||
void downloadJson(const QString & url, QJsonDocument * json);
|
||||
void downloadToFile(const QString & url, const QString & filePath);
|
||||
void downloadToBuffer(const DownloadDataType type, const QString & url);
|
||||
void download(const DownloadDataType type, const QString & urlStr, const char * header, const QString & filePath);
|
||||
QByteArray * getDownloadBuffer();
|
||||
const bool isSuccess();
|
||||
|
||||
static QString downloadDataTypeToString(const DownloadDataType val);
|
||||
|
||||
private slots:
|
||||
void onDownloadFinished(QNetworkReply * reply, DownloadDataType ddt);
|
||||
|
||||
private:
|
||||
UpdateStatus *m_status;
|
||||
QNetworkAccessManager m_manager;
|
||||
QNetworkRequest m_request;
|
||||
QNetworkReply *m_reply;
|
||||
QByteArray *m_buffer;
|
||||
QFile *m_file;
|
||||
QUrl m_url;
|
||||
bool m_success;
|
||||
|
||||
};
|
||||
@@ -30,29 +30,28 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QTimer>
|
||||
|
||||
UpdateOptionsDialog::UpdateOptionsDialog(QWidget * parent, UpdateFactories * factories, const int idx, const bool isRun) :
|
||||
UpdateOptionsDialog::UpdateOptionsDialog(QWidget * parent, UpdateInterface * iface, const int idx, const bool isRun) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::UpdateOptionsDialog),
|
||||
factories(factories),
|
||||
iface(iface),
|
||||
params(iface->params()),
|
||||
idx(idx),
|
||||
isRun(isRun)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (!isRun)
|
||||
factories->resetEnvironment(idx);
|
||||
iface->resetEnvironment();
|
||||
|
||||
params = factories->getParams(idx);
|
||||
setWindowTitle(tr("%1 %2").arg(iface->name()).arg(tr("Options")));
|
||||
|
||||
setWindowTitle(tr("%1 %2").arg(factories->name(idx)).arg(tr("Options")));
|
||||
ui->txtreleaseCurrent->setText(iface->releaseCurrent());
|
||||
|
||||
ui->txtCurrentRelease->setText(factories->currentRelease(idx));
|
||||
|
||||
connect(ui->btnClearRelease, &QPushButton::clicked, [=]() {
|
||||
connect(ui->btnReleaseClear, &QPushButton::clicked, [=]() {
|
||||
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear current release information. Are you sure?"),
|
||||
QMessageBox::Yes |QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
factories->clearRelease(idx);
|
||||
ui->txtCurrentRelease->setText(factories->currentRelease(idx));
|
||||
iface->releaseClear();
|
||||
ui->txtreleaseCurrent->setText(iface->releaseCurrent());
|
||||
emit changed(idx);
|
||||
|
||||
}
|
||||
@@ -251,7 +250,7 @@ UpdateOptionsDialog::UpdateOptionsDialog(QWidget * parent, UpdateFactories * fac
|
||||
}
|
||||
|
||||
if (!isRun)
|
||||
factories->saveAssetSettings(idx);
|
||||
iface->assetSettingsSave();
|
||||
|
||||
QDialog::accept();
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ class UpdateOptionsDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UpdateOptionsDialog(QWidget * parent, UpdateFactories * factories, const int idx, const bool isRun);
|
||||
UpdateOptionsDialog(QWidget * parent, UpdateInterface * iface, const int idx, const bool isRun);
|
||||
virtual ~UpdateOptionsDialog();
|
||||
|
||||
signals:
|
||||
@@ -53,10 +53,10 @@ class UpdateOptionsDialog : public QDialog
|
||||
|
||||
private:
|
||||
Ui::UpdateOptionsDialog *ui;
|
||||
UpdateFactories *factories;
|
||||
UpdateInterface *iface;
|
||||
UpdateParameters *params;
|
||||
const int idx;
|
||||
const bool isRun;
|
||||
UpdateParameters *params;
|
||||
|
||||
QVector<QComboBox *> cboAssetFilterTypes;
|
||||
QVector<QLineEdit *> leAssetFilters;
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCurrentRelease">
|
||||
<widget class="QLabel" name="lblreleaseCurrent">
|
||||
<property name="text">
|
||||
<string>Current Release:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="txtCurrentRelease">
|
||||
<widget class="QLabel" name="txtreleaseCurrent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -43,7 +43,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClearRelease">
|
||||
<widget class="QPushButton" name="btnReleaseClear">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 "updateparameters.h"
|
||||
#include "constants.h"
|
||||
|
||||
UpdateParameters::UpdateParameters(QObject * parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
logLevel = 0;
|
||||
flags = 0;
|
||||
decompressDirUseDwnld = true;
|
||||
updateDirUseSD = true;
|
||||
}
|
||||
|
||||
UpdateParameters::AssetParams & UpdateParameters::addAsset()
|
||||
{
|
||||
AssetParams ap;
|
||||
ap.processes = 0;
|
||||
ap.flags = 0;
|
||||
ap.filterType = UFT_None;
|
||||
ap.maxExpected = 0;
|
||||
ap.copyFilterType = UFT_None;
|
||||
assets.append(ap);
|
||||
|
||||
return assets[assets.size() - 1];
|
||||
}
|
||||
|
||||
QString UpdateParameters::buildFilterPattern(const UpdateFilterType filterType, const QString & filter)
|
||||
{
|
||||
QString pattern(filter);
|
||||
|
||||
pattern.replace("%FWFLAVOUR%", fwFlavour);
|
||||
pattern.replace("%LANGUAGE%", language);
|
||||
|
||||
switch ((int)filterType) {
|
||||
case UFT_Exact:
|
||||
pattern.prepend("^");
|
||||
pattern.append("$");
|
||||
break;
|
||||
case UFT_Startswith:
|
||||
pattern.prepend("^");
|
||||
break;
|
||||
case UFT_Endswith:
|
||||
pattern.append("$");
|
||||
break;
|
||||
case UFT_Contains:
|
||||
case UFT_Pattern:
|
||||
break;
|
||||
default:
|
||||
pattern = "";
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// static
|
||||
QStringList UpdateParameters::updateFilterTypeList()
|
||||
{
|
||||
return { tr("None"), tr("Exact"), tr("Startswith"), tr("Endswith"), tr("Contains"), tr("Pattern") };
|
||||
}
|
||||
|
||||
// static
|
||||
QString UpdateParameters::updateFilterTypeToString(UpdateFilterType uft)
|
||||
{
|
||||
return updateFilterTypeList().value(uft, CPN_STR_UNKNOWN_ITEM);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 <QtCore>
|
||||
|
||||
class UpdateParameters : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum UpdateFilterType {
|
||||
UFT_None,
|
||||
UFT_Exact,
|
||||
UFT_Startswith,
|
||||
UFT_Endswith,
|
||||
UFT_Contains,
|
||||
UFT_Pattern,
|
||||
};
|
||||
|
||||
static QStringList updateFilterTypeList();
|
||||
|
||||
static QString updateFilterTypeToString(UpdateFilterType uft);
|
||||
|
||||
struct AssetParams {
|
||||
int processes;
|
||||
int flags;
|
||||
UpdateFilterType filterType;
|
||||
QString filter;
|
||||
int maxExpected;
|
||||
QString destSubDir;
|
||||
UpdateFilterType copyFilterType;
|
||||
QString copyFilter;
|
||||
};
|
||||
|
||||
int flags;
|
||||
int logLevel;
|
||||
QString fwFlavour;
|
||||
QString language;
|
||||
int releaseChannel;
|
||||
QString releaseCurrent;
|
||||
QString releaseUpdate;
|
||||
QString downloadDir;
|
||||
bool decompressDirUseDwnld;
|
||||
QString decompressDir;
|
||||
QString sdDir;
|
||||
bool updateDirUseSD;
|
||||
QString updateDir;
|
||||
QVector<AssetParams> assets;
|
||||
|
||||
UpdateParameters(QObject * parent);
|
||||
virtual ~UpdateParameters() {}
|
||||
|
||||
AssetParams & addAsset();
|
||||
QString buildFilterPattern(const UpdateFilterType filterType, const QString & filter);
|
||||
};
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "updates.h"
|
||||
#include "updateinterface.h"
|
||||
#include "updatefactories.h"
|
||||
#include "updatesdialog.h"
|
||||
#include "progressdialog.h"
|
||||
#include "progresswidget.h"
|
||||
@@ -94,8 +94,9 @@ void Updates::autoUpdates(bool interactive)
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
factories->setRunUpdate(it.value());
|
||||
factories->updateRelease(it.value());
|
||||
UpdateInterface *iface = factories->instance(it.value());
|
||||
iface->setRunUpdate();
|
||||
iface->releaseUpdate();
|
||||
}
|
||||
|
||||
runUpdate();
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
#include <QMessageBox>
|
||||
|
||||
UpdateSDCard::UpdateSDCard(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
UpdateInterface(parent, CID_SDCard, tr("SD Card"))
|
||||
{
|
||||
init(CID_SDCard, tr("SD Card"), QString(GH_REPOS_EDGETX).append("/edgetx-sdcard"));
|
||||
init(QString(GH_API_REPOS_EDGETX).append("/edgetx-sdcard"), "Latest");
|
||||
}
|
||||
|
||||
void UpdateSDCard::initAssetSettings()
|
||||
void UpdateSDCard::assetSettingsInit()
|
||||
{
|
||||
if (!isValidSettingsIndex())
|
||||
if (!isSettingsIndexValid())
|
||||
return;
|
||||
|
||||
g.component[id()].initAllAssets();
|
||||
@@ -49,7 +49,22 @@ void UpdateSDCard::initAssetSettings()
|
||||
|
||||
bool UpdateSDCard::flagAssets()
|
||||
{
|
||||
progressMessage(tr("Flagging assets"));
|
||||
status()->progressMessage(tr("Flagging assets"));
|
||||
|
||||
QJsonDocument *json = new QJsonDocument();
|
||||
|
||||
const QString jsonFile("sdcard.json");
|
||||
|
||||
if (!retrieveAssetsJsonFile(jsonFile, json)) {
|
||||
status()->reportProgress(tr("Unable to retrieve asset '%1' from release '%2'").arg(jsonFile).arg(repo()->releases()->name()), QtDebugMsg);
|
||||
// assume older release where file not an asset
|
||||
if (!retrieveRepoJsonFile(jsonFile, json)) {
|
||||
status()->reportProgress(tr("Unable to retrieve file '%1' from repo '%2'").arg(jsonFile).arg(repo()->path()), QtCriticalMsg);
|
||||
delete json;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"targets": [
|
||||
@@ -57,24 +72,14 @@ bool UpdateSDCard::flagAssets()
|
||||
["FrSky Horus X10", "x10-", "c480x272"],
|
||||
*/
|
||||
|
||||
const QString mappingfile = "sdcard.json";
|
||||
const UpdateParameters::AssetParams & ap = params()->assets.at(0);
|
||||
|
||||
if (!downloadTextFileToBuffer(mappingfile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument *json = new QJsonDocument();
|
||||
|
||||
if (!convertDownloadToJson(json)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const UpdateParameters::AssetParams & ap = params->assets.at(0);
|
||||
|
||||
QRegularExpression filter(params->buildFilterPattern(ap.filterType, ap.filter), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression filter(params()->buildFilterPattern(ap.filterType, ap.filter), QRegularExpression::CaseInsensitiveOption);
|
||||
bool found = false;
|
||||
QString sdimage;
|
||||
|
||||
//qDebug() << *json;
|
||||
|
||||
if (json->isObject()) {
|
||||
const QJsonObject &obj = json->object();
|
||||
|
||||
@@ -100,7 +105,7 @@ bool UpdateSDCard::flagAssets()
|
||||
delete json;
|
||||
|
||||
if (!found) {
|
||||
reportProgress(tr("Radio flavour %1 not listed in %2").arg(params->fwFlavour).arg(mappingfile), QtCriticalMsg);
|
||||
status()->reportProgress(tr("Radio flavour '%1' not listed in '%2'").arg(params()->fwFlavour).arg(jsonFile), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -108,7 +113,7 @@ bool UpdateSDCard::flagAssets()
|
||||
sd.filterType = UpdateParameters::UFT_Startswith;
|
||||
sd.filter = sdimage;
|
||||
|
||||
if (!getSetAssets(sd))
|
||||
if (!setFilteredAssets(sd))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -33,7 +33,6 @@ class UpdateSDCard : public UpdateInterface
|
||||
virtual ~UpdateSDCard() {}
|
||||
|
||||
protected:
|
||||
virtual void initAssetSettings() override;
|
||||
|
||||
virtual void assetSettingsInit() override;
|
||||
virtual bool flagAssets() override;
|
||||
};
|
||||
|
||||
@@ -139,7 +139,7 @@ UpdatesDialog::UpdatesDialog(QWidget * parent, UpdateFactories * factories) :
|
||||
|
||||
QGridLayout *grid = new QGridLayout();
|
||||
|
||||
QLabel *h1 = new QLabel();
|
||||
QCheckBox *h1 = new QCheckBox();
|
||||
grid->addWidget(h1, row, col++);
|
||||
|
||||
QLabel *h2 = new QLabel(tr("Name"));
|
||||
@@ -166,13 +166,15 @@ UpdatesDialog::UpdatesDialog(QWidget * parent, UpdateFactories * factories) :
|
||||
const int i = it.value();
|
||||
const QString name = it.key();
|
||||
|
||||
UpdateInterface *iface = factories->instance(i);
|
||||
|
||||
row++;
|
||||
col = 0;
|
||||
|
||||
msg->setText(tr("Retrieving latest release information for %1").arg(name));
|
||||
chkUpdate[i] = new QCheckBox();
|
||||
chkUpdate[i]->setProperty("index", i);
|
||||
chkUpdate[i]->setChecked(!factories->isLatestRelease(i));
|
||||
chkUpdate[i]->setChecked(!iface->isReleaseLatest());
|
||||
grid->addWidget(chkUpdate[i], row, col++);
|
||||
grid->setAlignment(chkUpdate[i], Qt::AlignHCenter);
|
||||
|
||||
@@ -184,26 +186,31 @@ UpdatesDialog::UpdatesDialog(QWidget * parent, UpdateFactories * factories) :
|
||||
cboRelChannel[i]->setCurrentIndex(g.component[i].releaseChannel());
|
||||
grid->addWidget(cboRelChannel[i], row, col++);
|
||||
|
||||
lblCurrentRel[i] = new QLabel(factories->currentRelease(i));
|
||||
lblCurrentRel[i] = new QLabel(iface->releaseCurrent());
|
||||
grid->addWidget(lblCurrentRel[i], row, col++);
|
||||
|
||||
cboUpdateRel[i] = new QComboBox();
|
||||
cboUpdateRel[i]->addItems(factories->releases(i));
|
||||
cboUpdateRel[i]->addItems(iface->releaseList());
|
||||
grid->addWidget(cboUpdateRel[i], row, col++);
|
||||
|
||||
connect(cboRelChannel[i], QOverload<int>::of(&QComboBox::currentIndexChanged), [=] (const int index) {
|
||||
factories->setReleaseChannel(i, index);
|
||||
iface->setReleaseChannel(index);
|
||||
chkUpdate[i]->setChecked(!iface->isReleaseLatest());
|
||||
cboUpdateRel[i]->clear();
|
||||
cboUpdateRel[i]->addItems(factories->releases(i));
|
||||
cboUpdateRel[i]->addItems(iface->releaseList());
|
||||
});
|
||||
|
||||
connect(cboUpdateRel[i], QOverload<int>::of(&QComboBox::currentIndexChanged), [=] (const int index) {
|
||||
chkUpdate[i]->setChecked(cboUpdateRel[i]->currentText() != lblCurrentRel[i]->text());
|
||||
});
|
||||
|
||||
btnOptions[i] = new QPushButton(tr("Options"));
|
||||
connect(btnOptions[i], &QPushButton::clicked, [=]() {
|
||||
UpdateOptionsDialog *dlg = new UpdateOptionsDialog(this, factories, i, true);
|
||||
UpdateOptionsDialog *dlg = new UpdateOptionsDialog(this, iface, i, true);
|
||||
connect(dlg, &UpdateOptionsDialog::changed, [=](const int i) {
|
||||
chkUpdate[i]->setChecked(!factories->isLatestRelease(i));
|
||||
lblCurrentRel[i]->setText(factories->currentRelease(i));
|
||||
cboUpdateRel[i]->setCurrentText(factories->updateRelease(i));
|
||||
chkUpdate[i]->setChecked(!iface->isReleaseLatest());
|
||||
lblCurrentRel[i]->setText(iface->releaseCurrent());
|
||||
cboUpdateRel[i]->setCurrentText(iface->releaseUpdate());
|
||||
});
|
||||
dlg->exec();
|
||||
dlg->deleteLater();
|
||||
@@ -214,6 +221,14 @@ UpdatesDialog::UpdatesDialog(QWidget * parent, UpdateFactories * factories) :
|
||||
|
||||
ui->grpComponents->setLayout(grid);
|
||||
|
||||
connect(h1, &QCheckBox::clicked, [=] (bool checked) {
|
||||
QMapIterator<QString, int> it(sortedCompList);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
chkUpdate[it.value()]->setChecked(checked);
|
||||
}
|
||||
});
|
||||
|
||||
QPushButton *btnSaveAsDefaults = new QPushButton(tr("Save as Defaults"));
|
||||
ui->buttonBox->addButton(btnSaveAsDefaults, QDialogButtonBox::ActionRole);
|
||||
connect(btnSaveAsDefaults, &QPushButton::clicked, [=]() {
|
||||
@@ -272,8 +287,8 @@ void UpdatesDialog::accept()
|
||||
|
||||
if (chkUpdate[i]->isChecked()) {
|
||||
cnt++;
|
||||
UpdateParameters *params = factories->getParams(i);
|
||||
params->updateRelease = cboUpdateRel[i]->currentText();
|
||||
UpdateParameters *params = factories->instance(i)->params();
|
||||
params->releaseUpdate = cboUpdateRel[i]->currentText();
|
||||
params->flags |= UpdateInterface::UPDFLG_Update;
|
||||
params->downloadDir = ui->leDownloadDir->text();
|
||||
params->decompressDirUseDwnld = ui->chkDecompressDirUseDwnld->isChecked();
|
||||
@@ -315,6 +330,6 @@ void UpdatesDialog::saveAsDefaults()
|
||||
it.next();
|
||||
const int i = it.value();
|
||||
g.component[i].releaseChannel((ComponentData::ReleaseChannel)cboRelChannel[i]->currentIndex());
|
||||
factories->saveAssetSettings(i);
|
||||
factories->instance(i)->assetSettingsSave();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "updateinterface.h"
|
||||
#include "updatefactories.h"
|
||||
#include "appdata.h"
|
||||
|
||||
#include <QDialog>
|
||||
@@ -44,8 +44,6 @@ class UpdatesDialog : public QDialog
|
||||
UpdatesDialog(QWidget * parent, UpdateFactories * factories);
|
||||
virtual ~UpdatesDialog();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
virtual void accept();
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
UpdateSounds::UpdateSounds(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
UpdateInterface(parent, CID_Sounds, tr("Sounds"))
|
||||
{
|
||||
init(CID_Sounds, tr("Sounds"), QString(GH_REPOS_EDGETX).append("/edgetx-sdcard-sounds"));
|
||||
init(QString(GH_API_REPOS_EDGETX).append("/edgetx-sdcard-sounds"));
|
||||
langPacks = new QStandardItemModel();
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ UpdateSounds::~UpdateSounds()
|
||||
delete langPacks;
|
||||
}
|
||||
|
||||
void UpdateSounds::initAssetSettings()
|
||||
void UpdateSounds::assetSettingsInit()
|
||||
{
|
||||
if (!isValidSettingsIndex())
|
||||
if (!isSettingsIndexValid())
|
||||
return;
|
||||
|
||||
g.component[id()].initAllAssets();
|
||||
@@ -57,29 +57,20 @@ void UpdateSounds::initAssetSettings()
|
||||
|
||||
bool UpdateSounds::flagAssets()
|
||||
{
|
||||
progressMessage(tr("Processing available sounds"));
|
||||
|
||||
QString pattern("sounds.json");
|
||||
assets->setFilterPattern(pattern);
|
||||
|
||||
if (assets->count() < 0) {
|
||||
reportProgress(tr("Asset not found in release '%1' using filter pattern '%2'").arg(releases->name()).arg(pattern), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
else if (assets->count() > 1) {
|
||||
reportProgress(tr("%1 assets found when %2 expected in release '%3' using filter pattern '%4'")
|
||||
.arg(assets->count()).arg(1).arg(releases->name()).arg(pattern), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!downloadAssetToBuffer(assets->getSetId(0))) {
|
||||
return false;
|
||||
}
|
||||
status()->progressMessage(tr("Processing available sounds"));
|
||||
|
||||
QJsonDocument *json = new QJsonDocument();
|
||||
|
||||
if (!convertDownloadToJson(json)) {
|
||||
return false;
|
||||
const QString jsonFile("sounds.json");
|
||||
|
||||
if (!retrieveAssetsJsonFile(jsonFile, json)) {
|
||||
status()->reportProgress(tr("Unable to retrieve asset '%1' from release '%2'").arg(jsonFile).arg(repo()->releases()->name()), QtDebugMsg);
|
||||
// assume older release where file not an asset
|
||||
if (!retrieveRepoJsonFile(jsonFile, json)) {
|
||||
status()->reportProgress(tr("Unable to retrieve file '%1' from repo '%2'").arg(jsonFile).arg(repo()->path()), QtCriticalMsg);
|
||||
delete json;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -108,7 +99,7 @@ bool UpdateSounds::flagAssets()
|
||||
lang = langVariant.split("-").at(0);
|
||||
}
|
||||
|
||||
if (lang == params->language) {
|
||||
if (lang == params()->language) {
|
||||
QStandardItem * item = new QStandardItem();
|
||||
|
||||
if (!obj.value("language").isUndefined())
|
||||
@@ -129,7 +120,7 @@ bool UpdateSounds::flagAssets()
|
||||
delete json;
|
||||
|
||||
if (langPacks->rowCount() < 1) {
|
||||
reportProgress(tr("Language %1 not listed in %2").arg(params->language).arg(pattern), QtCriticalMsg);
|
||||
status()->reportProgress(tr("Language '%1' not listed in '%2'").arg(params()->language).arg(jsonFile), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -141,7 +132,7 @@ bool UpdateSounds::flagAssets()
|
||||
QItemSelectionModel *selItems = dlg->selectedItems();
|
||||
|
||||
if (!ok || !selItems->hasSelection()) {
|
||||
QMessageBox::warning(progress, CPN_STR_APP_NAME, tr("No language packs have been selected. Sounds update will be skipped!"));
|
||||
QMessageBox::warning(status()->progress(), CPN_STR_APP_NAME, tr("No language packs have been selected. Sounds update will be skipped!"));
|
||||
dlg->deleteLater();
|
||||
return true;
|
||||
}
|
||||
@@ -165,9 +156,9 @@ bool UpdateSounds::flagAssets()
|
||||
|
||||
bool UpdateSounds::flagLanguageAsset(QString lang)
|
||||
{
|
||||
progressMessage(tr("Flagging assets"));
|
||||
status()->progressMessage(tr("Flagging assets"));
|
||||
|
||||
params->language = lang;
|
||||
UpdateParameters::AssetParams ap = params->assets[0];
|
||||
return getSetAssets(ap);
|
||||
params()->language = lang;
|
||||
UpdateParameters::AssetParams ap = params()->assets[0];
|
||||
return setFilteredAssets(ap);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,8 @@ class UpdateSounds : public UpdateInterface
|
||||
virtual ~UpdateSounds();
|
||||
|
||||
protected:
|
||||
virtual void initAssetSettings() override;
|
||||
|
||||
virtual bool flagAssets() override;
|
||||
virtual void assetSettingsInit() override;
|
||||
|
||||
private:
|
||||
enum ItemModelDataRoles {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 "updatestatus.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
UpdateStatus::UpdateStatus(QObject * parent) :
|
||||
QObject(parent),
|
||||
m_progress(nullptr),
|
||||
m_logLevel(QtInfoMsg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UpdateStatus::reportProgress(QString text, QtMsgType type)
|
||||
{
|
||||
if (m_logLevel == QtDebugMsg ||
|
||||
(m_logLevel == QtInfoMsg && type > QtDebugMsg) ||
|
||||
(type < QtInfoMsg && type >= m_logLevel)) {
|
||||
if (m_progress) {
|
||||
m_progress->addMessage(text, type);
|
||||
if (m_logLevel == QtDebugMsg)
|
||||
qDebug() << text;
|
||||
}
|
||||
else
|
||||
qDebug() << text;
|
||||
}
|
||||
|
||||
if (type == QtCriticalMsg || type == QtFatalMsg)
|
||||
criticalMsg(text);
|
||||
}
|
||||
|
||||
void UpdateStatus::progressMessage(QString text)
|
||||
{
|
||||
if (m_progress)
|
||||
m_progress->setInfo(text);
|
||||
else
|
||||
qDebug() << text;
|
||||
}
|
||||
|
||||
void UpdateStatus::criticalMsg(QString msg)
|
||||
{
|
||||
QMessageBox::critical(m_progress, tr("Update Interface"), msg);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 "progresswidget.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class UpdateStatus : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UpdateStatus(QObject * parent);
|
||||
virtual ~UpdateStatus() {}
|
||||
|
||||
void setInfo(QString text) { if (m_progress) m_progress->setInfo(text); }
|
||||
void setLogLevel(int logLevel) { m_logLevel = logLevel; }
|
||||
void setValue(int val) { if (m_progress) m_progress->setValue(val); }
|
||||
|
||||
void setMaximum(int val) { if (m_progress) m_progress->setMaximum(val); }
|
||||
int maximum() { return m_progress ? m_progress->maximum() : 0; }
|
||||
|
||||
void setProgress(ProgressWidget * progress) { m_progress = progress; }
|
||||
ProgressWidget * progress() { return m_progress; }
|
||||
|
||||
void reportProgress(QString text, QtMsgType type = QtInfoMsg);
|
||||
void progressMessage(QString text);
|
||||
void criticalMsg(QString msg);
|
||||
|
||||
private:
|
||||
ProgressWidget *m_progress;
|
||||
int m_logLevel;
|
||||
};
|
||||
@@ -22,14 +22,14 @@
|
||||
#include "updatethemes.h"
|
||||
|
||||
UpdateThemes::UpdateThemes(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
UpdateInterface(parent, CID_Themes, tr("Themes"))
|
||||
{
|
||||
init(CID_Themes, tr("Themes"), QString(GH_REPOS_EDGETX).append("/themes"));
|
||||
init(QString(GH_API_REPOS_EDGETX).append("/themes"));
|
||||
}
|
||||
|
||||
void UpdateThemes::initAssetSettings()
|
||||
void UpdateThemes::assetSettingsInit()
|
||||
{
|
||||
if (!isValidSettingsIndex())
|
||||
if (!isSettingsIndexValid())
|
||||
return;
|
||||
|
||||
g.component[id()].initAllAssets();
|
||||
|
||||
@@ -33,6 +33,5 @@ class UpdateThemes : public UpdateInterface
|
||||
virtual ~UpdateThemes() {}
|
||||
|
||||
protected:
|
||||
virtual void initAssetSettings() override;
|
||||
|
||||
virtual void assetSettingsInit() override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user