Refactor firmware and companion updates plus add extra supporting components
@@ -25,11 +25,6 @@ set(COMPANION_OSX_APP_BUNDLE_NAME "EdgeTX Companion ${VERSION_MAJOR}.${VERSION_M
|
||||
# the binary (default homebrew path)
|
||||
set(DFU_UTIL_PATH "/usr/local/bin/dfu-util")
|
||||
|
||||
option(ALLOW_NIGHTLY_BUILDS "Allow nightly builds download / update") # Disabled by default
|
||||
if(ALLOW_NIGHTLY_BUILDS)
|
||||
add_definitions(-DALLOW_NIGHTLY_BUILDS)
|
||||
endif(ALLOW_NIGHTLY_BUILDS)
|
||||
|
||||
option(DEBUG_STORAGE_IMPORT "Turn on debug output for storage import") # Disabled by default
|
||||
if(DEBUG_STORAGE_IMPORT)
|
||||
add_definitions(-DDEBUG_STORAGE_IMPORT)
|
||||
@@ -198,6 +193,7 @@ add_subdirectory(storage)
|
||||
add_subdirectory(thirdparty/qcustomplot)
|
||||
add_subdirectory(thirdparty/maxlibqt/src/widgets)
|
||||
add_subdirectory(thirdparty/miniz)
|
||||
add_subdirectory(updates)
|
||||
|
||||
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "Enable testing" FORCE)
|
||||
set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "Enable parse tools" FORCE)
|
||||
@@ -213,12 +209,9 @@ set(companion_SRCS
|
||||
modelslist.cpp
|
||||
labels.cpp
|
||||
apppreferencesdialog.cpp
|
||||
fwpreferencesdialog.cpp
|
||||
burnconfigdialog.cpp
|
||||
multimodelprinter.cpp
|
||||
comparedialog.cpp
|
||||
releasenotesdialog.cpp
|
||||
releasenotesfirmwaredialog.cpp
|
||||
customizesplashdialog.cpp
|
||||
radiointerface.cpp
|
||||
progresswidget.cpp
|
||||
@@ -231,7 +224,6 @@ set(companion_SRCS
|
||||
printdialog.cpp
|
||||
modelprinter.cpp
|
||||
logsdialog.cpp
|
||||
downloaddialog.cpp
|
||||
splashlibrarydialog.cpp
|
||||
mainwindow.cpp
|
||||
companion.cpp
|
||||
@@ -245,13 +237,10 @@ set(companion_SRCS
|
||||
|
||||
set(companion_MOC_HDRS
|
||||
apppreferencesdialog.h
|
||||
fwpreferencesdialog.h
|
||||
burnconfigdialog.h
|
||||
comparedialog.h
|
||||
printdialog.h
|
||||
logsdialog.h
|
||||
releasenotesdialog.h
|
||||
releasenotesfirmwaredialog.h
|
||||
customizesplashdialog.h
|
||||
splashlibrarydialog.h
|
||||
splashlabel.h
|
||||
@@ -262,7 +251,6 @@ set(companion_MOC_HDRS
|
||||
process_sync.h
|
||||
flashfirmwaredialog.h
|
||||
flasheepromdialog.h
|
||||
downloaddialog.h
|
||||
mdichild.h
|
||||
mainwindow.h
|
||||
radionotfound.h
|
||||
@@ -282,9 +270,7 @@ set(companion_UIS
|
||||
comparedialog.ui
|
||||
logsdialog.ui
|
||||
apppreferencesdialog.ui
|
||||
fwpreferencesdialog.ui
|
||||
burnconfigdialog.ui
|
||||
downloaddialog.ui
|
||||
printdialog.ui
|
||||
htmldialog.ui
|
||||
customizesplashdialog.ui
|
||||
@@ -306,7 +292,7 @@ qt5_wrap_ui(companion_SRCS ${companion_UIS})
|
||||
qt5_wrap_cpp(companion_SRCS ${companion_MOC_HDRS})
|
||||
|
||||
add_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${icon_RC})
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit qcustomplot miniz shared ${CPN_COMMON_LIB})
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit qcustomplot miniz shared updates ${CPN_COMMON_LIB})
|
||||
|
||||
PrintTargetReport("${COMPANION_NAME}")
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "apppreferencesdialog.h"
|
||||
#include "ui_apppreferencesdialog.h"
|
||||
#include "mainwindow.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "storage.h"
|
||||
#if defined(JOYSTICKS)
|
||||
@@ -30,14 +29,16 @@
|
||||
#endif
|
||||
#include "moduledata.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "updates/updateinterface.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
AppPreferencesDialog::AppPreferencesDialog(QWidget * parent) :
|
||||
AppPreferencesDialog::AppPreferencesDialog(QWidget * parent, UpdateFactories * factories) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AppPreferencesDialog),
|
||||
updateLock(false),
|
||||
mainWinHasDirtyChild(false)
|
||||
mainWinHasDirtyChild(false),
|
||||
factories(factories)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("apppreferences.png"));
|
||||
@@ -73,9 +74,6 @@ void AppPreferencesDialog::accept()
|
||||
{
|
||||
Profile & profile = g.currentProfile();
|
||||
|
||||
g.autoCheckApp(ui->autoCheckCompanion->isChecked());
|
||||
g.OpenTxBranch(AppData::DownloadBranchType(ui->OpenTxBranch->currentIndex()));
|
||||
g.autoCheckFw(ui->autoCheckFirmware->isChecked());
|
||||
g.showSplash(ui->showSplash->isChecked());
|
||||
g.promptProfile(ui->chkPromptProfile->isChecked());
|
||||
g.simuSW(ui->simuSW->isChecked());
|
||||
@@ -101,6 +99,28 @@ void AppPreferencesDialog::accept()
|
||||
g.jsSupport(false);
|
||||
g.jsCtrl(0);
|
||||
}
|
||||
|
||||
// Updates tab
|
||||
|
||||
g.updateCheckFreq(AppData::UpdateCheckFreq(ui->cboUpdateCheckFreq->currentIndex()));
|
||||
g.downloadDir(ui->leDownloadDir->text());
|
||||
|
||||
g.decompressUseDwnld(ui->chkDecompressUseDwnld->isChecked());
|
||||
g.decompressDir(ui->leDecompressDir->text());
|
||||
|
||||
g.updateUseSD(ui->chkUpdateUseSD->isChecked());
|
||||
g.updateDir(ui->leUpdateDir->text());
|
||||
|
||||
QMapIterator<QString, int> it(factories->sortedComponentsList());
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
int i = it.value();
|
||||
|
||||
g.component[i].checkForUpdate(chkCheckForUpdate[i]->isChecked());
|
||||
g.component[i].releaseChannel((ComponentData::ReleaseChannel)cboReleaseChannel[i]->currentIndex());
|
||||
}
|
||||
|
||||
profile.defaultInternalModule(ui->defaultInternalModuleCB->currentData().toInt());
|
||||
profile.channelOrder(ui->channelorderCB->currentIndex());
|
||||
profile.defaultMode(ui->stickmodeCB->currentIndex());
|
||||
@@ -169,11 +189,6 @@ void AppPreferencesDialog::initSettings()
|
||||
{
|
||||
const Profile & profile = g.currentProfile();
|
||||
|
||||
// Disable these for now, until online elements are implemented
|
||||
ui->autoCheckFirmware->setDisabled(true);
|
||||
ui->autoCheckCompanion->setDisabled(true);
|
||||
ui->OpenTxBranch->setDisabled(true);
|
||||
|
||||
ui->snapshotClipboardCKB->setChecked(g.snapToClpbrd());
|
||||
ui->burnFirmware->setChecked(profile.burnFirmware());
|
||||
ui->snapshotPath->setText(g.snapshotDir());
|
||||
@@ -183,18 +198,6 @@ void AppPreferencesDialog::initSettings()
|
||||
ui->snapshotPathButton->setDisabled(true);
|
||||
}
|
||||
|
||||
#if !defined(ALLOW_NIGHTLY_BUILDS)
|
||||
// remove nightly version option entirely unless it's the current one (because user might have nightly version also installed)
|
||||
if (g.OpenTxBranch() != AppData::BRANCH_NIGHTLY_UNSTABLE)
|
||||
ui->OpenTxBranch->removeItem(2);
|
||||
// if it's already selected, add a warning message
|
||||
else
|
||||
ui->updatesLayout->addWidget(new QLabel("<font color='red'>" % tr("Note: Nightly builds are not available in this version, Release/RC update channel will be used.") % "</font>", this));
|
||||
#endif
|
||||
ui->OpenTxBranch->setCurrentIndex(g.OpenTxBranch());
|
||||
|
||||
ui->autoCheckCompanion->setChecked(g.autoCheckApp());
|
||||
ui->autoCheckFirmware->setChecked(g.autoCheckFw());
|
||||
ui->showSplash->setChecked(g.showSplash());
|
||||
ui->chkPromptProfile->setChecked(g.promptProfile());
|
||||
ui->historySize->setValue(g.historySize());
|
||||
@@ -303,6 +306,134 @@ void AppPreferencesDialog::initSettings()
|
||||
}
|
||||
|
||||
populateFirmwareOptions(getBaseFirmware());
|
||||
|
||||
// Updates tab
|
||||
|
||||
ui->cboUpdateCheckFreq->addItems(AppData::updateCheckFreqsList());
|
||||
|
||||
connect(ui->btnResetUpdatesToDefaults, &QPushButton::clicked, [=]() {
|
||||
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Reset all update settings to defaults. Are you sure?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
for (int i = 0; i < MAX_COMPONENTS; i++) {
|
||||
if (g.component[i].existsOnDisk())
|
||||
g.getComponent(i).resetAll();
|
||||
}
|
||||
g.resetUpdatesSettings();
|
||||
QMessageBox::warning(this, CPN_STR_APP_NAME,
|
||||
tr("Update settings have been reset. You must restart Companion to avoid unexpected behaviour!"));
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->chkDecompressUseDwnld, &QCheckBox::toggled, [=](const bool checked) {
|
||||
if (!checked) {
|
||||
ui->leDecompressDir->setText(g.decompressDir());
|
||||
ui->leDecompressDir->setEnabled(true);
|
||||
ui->btnDecompressSelect->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
ui->leDecompressDir->setText(g.downloadDir());
|
||||
ui->leDecompressDir->setEnabled(false);
|
||||
ui->btnDecompressSelect->setEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->chkUpdateUseSD, &QCheckBox::toggled, [=](const bool checked) {
|
||||
if (!checked) {
|
||||
ui->leUpdateDir->setText(g.updateDir());
|
||||
ui->leUpdateDir->setEnabled(true);
|
||||
ui->btnUpdateSelect->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
ui->leUpdateDir->setText(g.currentProfile().sdPath());
|
||||
ui->leUpdateDir->setEnabled(false);
|
||||
ui->btnUpdateSelect->setEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnDownloadSelect, &QPushButton::clicked, [=]() {
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this,tr("Select your download folder"), g.downloadDir());
|
||||
if (!dirPath.isEmpty()) {
|
||||
ui->leDownloadDir->setText(dirPath);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnDecompressSelect, &QPushButton::clicked, [=]() {
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this,tr("Select your decompress folder"), g.decompressDir());
|
||||
if (!dirPath.isEmpty()) {
|
||||
ui->leDecompressDir->setText(dirPath);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnUpdateSelect, &QPushButton::clicked, [=]() {
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this,tr("Select your update destination folder"), g.updateDir());
|
||||
if (!dirPath.isEmpty()) {
|
||||
ui->leUpdateDir->setText(dirPath);
|
||||
}
|
||||
});
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
|
||||
QGridLayout *grid = new QGridLayout();
|
||||
|
||||
col++; // leave col 0 blank
|
||||
|
||||
QLabel *h1 = new QLabel(tr("Check"));
|
||||
grid->addWidget(h1, row, col++);
|
||||
|
||||
QLabel *h2 = new QLabel(tr("Release channel"));
|
||||
grid->addWidget(h2, row, col++);
|
||||
|
||||
QSpacerItem * spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||
grid->addItem(spacer, row, col++);
|
||||
|
||||
QMapIterator<QString, int> it(factories->sortedComponentsList());
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
int i = it.value();
|
||||
|
||||
row++;
|
||||
col = 0;
|
||||
|
||||
lblName[i] = new QLabel();
|
||||
grid->addWidget(lblName[i], row, col++);
|
||||
|
||||
chkCheckForUpdate[i] = new QCheckBox();
|
||||
grid->addWidget(chkCheckForUpdate[i], row, col++);
|
||||
grid->setAlignment(chkCheckForUpdate[i], Qt::AlignHCenter);
|
||||
|
||||
cboReleaseChannel[i] = new QComboBox();
|
||||
cboReleaseChannel[i]->addItems(ComponentData::releaseChannelsList());
|
||||
grid->addWidget(cboReleaseChannel[i], row, col++);
|
||||
}
|
||||
|
||||
ui->grpComponents->setLayout(grid);
|
||||
|
||||
loadUpdatesTab();
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::loadUpdatesTab()
|
||||
{
|
||||
ui->cboUpdateCheckFreq->setCurrentIndex(g.updateCheckFreq());
|
||||
ui->leDownloadDir->setText(g.downloadDir());
|
||||
// trigger toggled signal by changing design value and then setting to saved value
|
||||
ui->chkDecompressUseDwnld->setChecked(!ui->chkDecompressUseDwnld->isChecked());
|
||||
ui->chkDecompressUseDwnld->setChecked(g.decompressUseDwnld());
|
||||
// trigger toggled signal by changing design value and then setting to saved value
|
||||
ui->chkUpdateUseSD->setChecked(!ui->chkUpdateUseSD->isChecked());
|
||||
ui->chkUpdateUseSD->setChecked(g.updateUseSD());
|
||||
|
||||
QMapIterator<QString, int> it(factories->sortedComponentsList());
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
int i = it.value();
|
||||
|
||||
lblName[i]->setText(it.key());
|
||||
chkCheckForUpdate[i]->setChecked(g.component[i].checkForUpdate());
|
||||
cboReleaseChannel[i]->setCurrentIndex(g.component[i].releaseChannel());
|
||||
}
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_libraryPathButton_clicked()
|
||||
|
||||
@@ -18,25 +18,28 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _APPPREFERENCESDIALOG_H_
|
||||
#define _APPPREFERENCESDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "appdata.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QCheckBox>
|
||||
#include "eeprominterface.h"
|
||||
#include <QComboBox>
|
||||
|
||||
namespace Ui {
|
||||
class AppPreferencesDialog;
|
||||
}
|
||||
|
||||
class Joystick;
|
||||
class UpdateFactories;
|
||||
|
||||
class AppPreferencesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AppPreferencesDialog(QWidget * parent = 0);
|
||||
explicit AppPreferencesDialog(QWidget * parent, UpdateFactories * factories);
|
||||
~AppPreferencesDialog();
|
||||
|
||||
Joystick * joystick;
|
||||
@@ -84,6 +87,12 @@ class AppPreferencesDialog : public QDialog
|
||||
QMap<QString, QCheckBox *> optionsCheckBoxes;
|
||||
bool updateLock;
|
||||
bool mainWinHasDirtyChild;
|
||||
};
|
||||
|
||||
#endif // _APPPREFERENCESDIALOG_H_
|
||||
UpdateFactories *factories;
|
||||
QLabel *lblName[MAX_COMPONENTS];
|
||||
QCheckBox *chkCheckForUpdate[MAX_COMPONENTS];
|
||||
QComboBox *cboReleaseChannel[MAX_COMPONENTS];
|
||||
|
||||
void loadUpdatesTab();
|
||||
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
@@ -45,7 +45,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="profileTab">
|
||||
<attribute name="title">
|
||||
@@ -732,7 +732,7 @@ Mode 4:
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="15" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QCheckBox" name="backupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@@ -745,8 +745,8 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="22" column="0">
|
||||
<widget class="QLabel" name="ge_label">
|
||||
<item row="6" column="0" rowspan="3">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -754,36 +754,89 @@ Mode 4:
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Google Earth Executable</string>
|
||||
<string>Startup Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="OpenTxBranch">
|
||||
<item row="22" column="0" colspan="2">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Releases (stable)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Release candidates (testing)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nightly builds (unstable)</string>
|
||||
</property>
|
||||
</item>
|
||||
<property name="text">
|
||||
<string>Remember</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<item row="23" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="opt_appDebugLog">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Keep a log of all debugging messages generated by the desktop Companion/Simulator applications. An EdgeTX developer may request this to help diagnose an issue.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Application (Companion/Simulator)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="opt_fwTraceLog">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Keep a log of all messages generated by the radio firmware when running in Simulator. This is the same information one would also see in the Simulator <span style=" font-style:italic;">Debug Output</span> window.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Radio Firmware (in Simulator)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="15" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="23" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Output Logging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="chkPromptProfile">
|
||||
<property name="text">
|
||||
<string>Prompt for radio profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<widget class="QComboBox" name="splashincludeCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
@@ -803,20 +856,86 @@ Mode 4:
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<item row="19" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="showSplash">
|
||||
<property name="text">
|
||||
<string>Show splash screen</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Action on New Model</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>User Splash Screens</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="0">
|
||||
<widget class="QLabel" name="ge_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Google Earth Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="ge_lineedit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ge_pathButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="0,1">
|
||||
<property name="spacing">
|
||||
@@ -853,41 +972,50 @@ Mode 4:
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="showSplash">
|
||||
<property name="text">
|
||||
<string>Show splash screen</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<item row="4" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="22" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="ge_lineedit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ge_pathButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<item row="17" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash Screen Library</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="24" column="0">
|
||||
<widget class="QLabel" name="lbl_appLogsDir">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output Logs Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="opt_removeBlankSlots">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove empty model slots when deleting models (only applies for radios w/out categories)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="backupPath">
|
||||
@@ -911,93 +1039,10 @@ Mode 4:
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remember</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="25" column="0">
|
||||
<widget class="QLabel" name="lbl_appLogsDir">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output Logs Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" rowspan="3">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Startup Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="opt_removeBlankSlots">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove empty model slots when deleting models (only applies for radios w/out categories)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>User Splash Screens</string>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="cboNewModelAction"/>
|
||||
</item>
|
||||
<item row="24" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="opt_appDebugLog">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Keep a log of all debugging messages generated by the desktop Companion/Simulator applications. An EdgeTX developer may request this to help diagnose an issue.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Application (Companion/Simulator)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="opt_fwTraceLog">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Keep a log of all messages generated by the radio firmware when running in Simulator. This is the same information one would also see in the Simulator <span style=" font-style:italic;">Debug Output</span> window.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Radio Firmware (in Simulator)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="25" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="appLogsDir">
|
||||
@@ -1018,20 +1063,7 @@ Mode 4:
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Action on New Model</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="1">
|
||||
<item row="18" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="libraryPath">
|
||||
@@ -1058,54 +1090,7 @@ Mode 4:
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash Screen Library</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Release channel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="24" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Output Logging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="23" column="0" colspan="2">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
@@ -1118,47 +1103,6 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<layout class="QVBoxLayout" name="updatesLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckFirmware">
|
||||
<property name="text">
|
||||
<string>Automatic check for firmware updates</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckCompanion">
|
||||
<property name="text">
|
||||
<string>Automatic check for Companion updates</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="20" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="chkPromptProfile">
|
||||
<property name="text">
|
||||
<string>Prompt for radio profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QComboBox" name="cboNewModelAction"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -1425,6 +1369,161 @@ Mode 4:
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="updateTab">
|
||||
<attribute name="title">
|
||||
<string>Update Settings</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCheckFreq">
|
||||
<property name="text">
|
||||
<string>Check frequency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboUpdateCheckFreq"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnResetUpdatesToDefaults">
|
||||
<property name="text">
|
||||
<string>Reset to Defaults</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpFolders">
|
||||
<property name="title">
|
||||
<string>Folders</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblDownloadDir">
|
||||
<property name="text">
|
||||
<string>Download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leDownloadDir"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lblUpdateDir">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="chkDecompressUseDwnld">
|
||||
<property name="text">
|
||||
<string>Create sub-folders in Download folder</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="leDecompressDir">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblDecompressDir">
|
||||
<property name="text">
|
||||
<string>Decompress</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="chkUpdateUseSD">
|
||||
<property name="text">
|
||||
<string>Use Radio Profile SD Structure</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="leUpdateDir">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="btnUpdateSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="btnDecompressSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnDownloadSelect">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpComponents">
|
||||
<property name="title">
|
||||
<string>Components</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>671</width>
|
||||
<height>240</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -1488,7 +1587,4 @@ Mode 4:
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="btnGrp_newModelActions"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
||||
@@ -405,7 +405,7 @@
|
||||
<file>themes/monochrome/16/compare.png</file>
|
||||
<file>themes/monochrome/16/saveas.png</file>
|
||||
<file>themes/monochrome/16/apppreferences.png</file>
|
||||
<file>themes/monochrome/16/fwpreferences.png</file>
|
||||
<file>themes/monochrome/16/download.png</file>
|
||||
<file>themes/monochrome/16/movedown.png</file>
|
||||
<file>themes/monochrome/16/currentmodel.png</file>
|
||||
<file>themes/monochrome/16/read_flash.png</file>
|
||||
@@ -449,7 +449,7 @@
|
||||
<file>themes/monochrome/24/compare.png</file>
|
||||
<file>themes/monochrome/24/saveas.png</file>
|
||||
<file>themes/monochrome/24/apppreferences.png</file>
|
||||
<file>themes/monochrome/24/fwpreferences.png</file>
|
||||
<file>themes/monochrome/24/download.png</file>
|
||||
<file>themes/monochrome/24/movedown.png</file>
|
||||
<file>themes/monochrome/24/currentmodel.png</file>
|
||||
<file>themes/monochrome/24/read_flash.png</file>
|
||||
@@ -493,7 +493,7 @@
|
||||
<file>themes/monochrome/32/compare.png</file>
|
||||
<file>themes/monochrome/32/saveas.png</file>
|
||||
<file>themes/monochrome/32/apppreferences.png</file>
|
||||
<file>themes/monochrome/32/fwpreferences.png</file>
|
||||
<file>themes/monochrome/32/download.png</file>
|
||||
<file>themes/monochrome/32/movedown.png</file>
|
||||
<file>themes/monochrome/32/currentmodel.png</file>
|
||||
<file>themes/monochrome/32/read_flash.png</file>
|
||||
@@ -537,7 +537,7 @@
|
||||
<file>themes/monochrome/48/compare.png</file>
|
||||
<file>themes/monochrome/48/saveas.png</file>
|
||||
<file>themes/monochrome/48/apppreferences.png</file>
|
||||
<file>themes/monochrome/48/fwpreferences.png</file>
|
||||
<file>themes/monochrome/48/download.png</file>
|
||||
<file>themes/monochrome/48/movedown.png</file>
|
||||
<file>themes/monochrome/48/currentmodel.png</file>
|
||||
<file>themes/monochrome/48/read_flash.png</file>
|
||||
@@ -581,7 +581,7 @@
|
||||
<file>themes/classic/16/compare.png</file>
|
||||
<file>themes/classic/16/saveas.png</file>
|
||||
<file>themes/classic/16/apppreferences.png</file>
|
||||
<file>themes/classic/16/fwpreferences.png</file>
|
||||
<file>themes/classic/16/download.png</file>
|
||||
<file>themes/classic/16/movedown.png</file>
|
||||
<file>themes/classic/16/currentmodel.png</file>
|
||||
<file>themes/classic/16/read_flash.png</file>
|
||||
@@ -625,7 +625,7 @@
|
||||
<file>themes/classic/24/compare.png</file>
|
||||
<file>themes/classic/24/saveas.png</file>
|
||||
<file>themes/classic/24/apppreferences.png</file>
|
||||
<file>themes/classic/24/fwpreferences.png</file>
|
||||
<file>themes/classic/24/download.png</file>
|
||||
<file>themes/classic/24/movedown.png</file>
|
||||
<file>themes/classic/24/currentmodel.png</file>
|
||||
<file>themes/classic/24/read_flash.png</file>
|
||||
@@ -669,7 +669,7 @@
|
||||
<file>themes/classic/32/compare.png</file>
|
||||
<file>themes/classic/32/saveas.png</file>
|
||||
<file>themes/classic/32/apppreferences.png</file>
|
||||
<file>themes/classic/32/fwpreferences.png</file>
|
||||
<file>themes/classic/32/download.png</file>
|
||||
<file>themes/classic/32/movedown.png</file>
|
||||
<file>themes/classic/32/currentmodel.png</file>
|
||||
<file>themes/classic/32/read_flash.png</file>
|
||||
@@ -713,7 +713,7 @@
|
||||
<file>themes/classic/48/compare.png</file>
|
||||
<file>themes/classic/48/saveas.png</file>
|
||||
<file>themes/classic/48/apppreferences.png</file>
|
||||
<file>themes/classic/48/fwpreferences.png</file>
|
||||
<file>themes/classic/48/download.png</file>
|
||||
<file>themes/classic/48/movedown.png</file>
|
||||
<file>themes/classic/48/currentmodel.png</file>
|
||||
<file>themes/classic/48/read_flash.png</file>
|
||||
@@ -757,7 +757,7 @@
|
||||
<file>themes/monoblue/16/compare.png</file>
|
||||
<file>themes/monoblue/16/saveas.png</file>
|
||||
<file>themes/monoblue/16/apppreferences.png</file>
|
||||
<file>themes/monoblue/16/fwpreferences.png</file>
|
||||
<file>themes/monoblue/16/download.png</file>
|
||||
<file>themes/monoblue/16/movedown.png</file>
|
||||
<file>themes/monoblue/16/currentmodel.png</file>
|
||||
<file>themes/monoblue/16/read_flash.png</file>
|
||||
@@ -801,7 +801,7 @@
|
||||
<file>themes/monoblue/24/compare.png</file>
|
||||
<file>themes/monoblue/24/saveas.png</file>
|
||||
<file>themes/monoblue/24/apppreferences.png</file>
|
||||
<file>themes/monoblue/24/fwpreferences.png</file>
|
||||
<file>themes/monoblue/24/download.png</file>
|
||||
<file>themes/monoblue/24/movedown.png</file>
|
||||
<file>themes/monoblue/24/currentmodel.png</file>
|
||||
<file>themes/monoblue/24/read_flash.png</file>
|
||||
@@ -845,7 +845,7 @@
|
||||
<file>themes/monoblue/32/compare.png</file>
|
||||
<file>themes/monoblue/32/saveas.png</file>
|
||||
<file>themes/monoblue/32/apppreferences.png</file>
|
||||
<file>themes/monoblue/32/fwpreferences.png</file>
|
||||
<file>themes/monoblue/32/download.png</file>
|
||||
<file>themes/monoblue/32/movedown.png</file>
|
||||
<file>themes/monoblue/32/currentmodel.png</file>
|
||||
<file>themes/monoblue/32/read_flash.png</file>
|
||||
@@ -889,7 +889,7 @@
|
||||
<file>themes/monoblue/48/compare.png</file>
|
||||
<file>themes/monoblue/48/saveas.png</file>
|
||||
<file>themes/monoblue/48/apppreferences.png</file>
|
||||
<file>themes/monoblue/48/fwpreferences.png</file>
|
||||
<file>themes/monoblue/48/download.png</file>
|
||||
<file>themes/monoblue/48/movedown.png</file>
|
||||
<file>themes/monoblue/48/currentmodel.png</file>
|
||||
<file>themes/monoblue/48/read_flash.png</file>
|
||||
@@ -933,7 +933,7 @@
|
||||
<file>themes/monowhite/16/compare.png</file>
|
||||
<file>themes/monowhite/16/saveas.png</file>
|
||||
<file>themes/monowhite/16/apppreferences.png</file>
|
||||
<file>themes/monowhite/16/fwpreferences.png</file>
|
||||
<file>themes/monowhite/16/download.png</file>
|
||||
<file>themes/monowhite/16/movedown.png</file>
|
||||
<file>themes/monowhite/16/currentmodel.png</file>
|
||||
<file>themes/monowhite/16/read_flash.png</file>
|
||||
@@ -977,7 +977,7 @@
|
||||
<file>themes/monowhite/24/compare.png</file>
|
||||
<file>themes/monowhite/24/saveas.png</file>
|
||||
<file>themes/monowhite/24/apppreferences.png</file>
|
||||
<file>themes/monowhite/24/fwpreferences.png</file>
|
||||
<file>themes/monowhite/24/download.png</file>
|
||||
<file>themes/monowhite/24/movedown.png</file>
|
||||
<file>themes/monowhite/24/currentmodel.png</file>
|
||||
<file>themes/monowhite/24/read_flash.png</file>
|
||||
@@ -1021,7 +1021,7 @@
|
||||
<file>themes/monowhite/32/compare.png</file>
|
||||
<file>themes/monowhite/32/saveas.png</file>
|
||||
<file>themes/monowhite/32/apppreferences.png</file>
|
||||
<file>themes/monowhite/32/fwpreferences.png</file>
|
||||
<file>themes/monowhite/32/download.png</file>
|
||||
<file>themes/monowhite/32/movedown.png</file>
|
||||
<file>themes/monowhite/32/currentmodel.png</file>
|
||||
<file>themes/monowhite/32/read_flash.png</file>
|
||||
@@ -1065,7 +1065,7 @@
|
||||
<file>themes/monowhite/48/compare.png</file>
|
||||
<file>themes/monowhite/48/saveas.png</file>
|
||||
<file>themes/monowhite/48/apppreferences.png</file>
|
||||
<file>themes/monowhite/48/fwpreferences.png</file>
|
||||
<file>themes/monowhite/48/download.png</file>
|
||||
<file>themes/monowhite/48/movedown.png</file>
|
||||
<file>themes/monowhite/48/currentmodel.png</file>
|
||||
<file>themes/monowhite/48/read_flash.png</file>
|
||||
@@ -1109,7 +1109,7 @@
|
||||
<file>themes/yerico/16/compare.png</file>
|
||||
<file>themes/yerico/16/saveas.png</file>
|
||||
<file>themes/yerico/16/apppreferences.png</file>
|
||||
<file>themes/yerico/16/fwpreferences.png</file>
|
||||
<file>themes/yerico/16/download.png</file>
|
||||
<file>themes/yerico/16/movedown.png</file>
|
||||
<file>themes/yerico/16/currentmodel.png</file>
|
||||
<file>themes/yerico/16/read_flash.png</file>
|
||||
@@ -1153,7 +1153,7 @@
|
||||
<file>themes/yerico/24/compare.png</file>
|
||||
<file>themes/yerico/24/saveas.png</file>
|
||||
<file>themes/yerico/24/apppreferences.png</file>
|
||||
<file>themes/yerico/24/fwpreferences.png</file>
|
||||
<file>themes/yerico/24/download.png</file>
|
||||
<file>themes/yerico/24/movedown.png</file>
|
||||
<file>themes/yerico/24/currentmodel.png</file>
|
||||
<file>themes/yerico/24/read_flash.png</file>
|
||||
@@ -1197,7 +1197,7 @@
|
||||
<file>themes/yerico/32/compare.png</file>
|
||||
<file>themes/yerico/32/saveas.png</file>
|
||||
<file>themes/yerico/32/apppreferences.png</file>
|
||||
<file>themes/yerico/32/fwpreferences.png</file>
|
||||
<file>themes/yerico/32/download.png</file>
|
||||
<file>themes/yerico/32/movedown.png</file>
|
||||
<file>themes/yerico/32/currentmodel.png</file>
|
||||
<file>themes/yerico/32/read_flash.png</file>
|
||||
@@ -1241,7 +1241,7 @@
|
||||
<file>themes/yerico/48/compare.png</file>
|
||||
<file>themes/yerico/48/saveas.png</file>
|
||||
<file>themes/yerico/48/apppreferences.png</file>
|
||||
<file>themes/yerico/48/fwpreferences.png</file>
|
||||
<file>themes/yerico/48/download.png</file>
|
||||
<file>themes/yerico/48/movedown.png</file>
|
||||
<file>themes/yerico/48/currentmodel.png</file>
|
||||
<file>themes/yerico/48/read_flash.png</file>
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CONSTANTS_H_
|
||||
#define _CONSTANTS_H_
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
@@ -84,5 +83,3 @@
|
||||
#define CPN_STR_SW_INDICATOR_REV QCoreApplication::translate("RawSwitch", "!") // Switch reversed logic (NOT) indicator.
|
||||
|
||||
#define EDGETX_HOME_PAGE_URL "https://edgetx.org"
|
||||
|
||||
#endif // _CONSTANTS_H_
|
||||
|
||||
@@ -1219,27 +1219,11 @@ unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getFirmwareBaseUrl()
|
||||
{
|
||||
return g.openTxCurrentDownloadBranchUrl() % QStringLiteral("firmware/");
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getFirmwareUrl()
|
||||
{
|
||||
return getFirmwareBaseUrl() % QString("getfw.php?fw=%1.bin").arg(QString(QUrl::toPercentEncoding(id)));
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getReleaseNotesUrl()
|
||||
{
|
||||
return QString("%1/downloads").arg(EDGETX_HOME_PAGE_URL);
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getStampUrl()
|
||||
{
|
||||
return getFirmwareBaseUrl() % QStringLiteral("stamp-opentx.txt");
|
||||
}
|
||||
|
||||
|
||||
// Firmware registrations
|
||||
// NOTE: "recognized" build options are defined in /radio/util/fwoptions.py
|
||||
|
||||
|
||||
@@ -111,11 +111,11 @@ class OpenTxFirmware: public Firmware
|
||||
|
||||
virtual Firmware * getFirmwareVariant(const QString & id);
|
||||
|
||||
virtual QString getStampUrl();
|
||||
virtual QString getStampUrl() { return ""; } // depreciated
|
||||
|
||||
virtual QString getReleaseNotesUrl();
|
||||
|
||||
virtual QString getFirmwareUrl();
|
||||
virtual QString getFirmwareUrl() { return ""; } // depreciated;
|
||||
|
||||
virtual int getCapability(Capability);
|
||||
|
||||
@@ -129,7 +129,7 @@ class OpenTxFirmware: public Firmware
|
||||
|
||||
protected:
|
||||
|
||||
QString getFirmwareBaseUrl();
|
||||
QString getFirmwareBaseUrl() { return ""; } // depreciated;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* 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 "fwpreferencesdialog.h"
|
||||
#include "ui_fwpreferencesdialog.h"
|
||||
#include "mainwindow.h"
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
|
||||
FirmwarePreferencesDialog::FirmwarePreferencesDialog(QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FirmwarePreferencesDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("fwpreferences.png"));
|
||||
initSettings();
|
||||
MainWindow * mw = qobject_cast<MainWindow *>(this->parent());
|
||||
if (mw)
|
||||
connect(mw, &MainWindow::firmwareDownloadCompleted, this, &FirmwarePreferencesDialog::initSettings);
|
||||
}
|
||||
|
||||
FirmwarePreferencesDialog::~FirmwarePreferencesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::initSettings()
|
||||
{
|
||||
ui->fwTypeLbl->setText(g.currentProfile().fwType());
|
||||
int version = g.fwRev.get(g.currentProfile().fwType());
|
||||
if (version > 0)
|
||||
ui->lastRevisionLbl->setText(index2version(version));
|
||||
else
|
||||
ui->lastRevisionLbl->setText(tr("Unknown"));
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::on_checkFWUpdates_clicked()
|
||||
{
|
||||
MainWindow * mw = qobject_cast<MainWindow *>(this->parent());
|
||||
if (mw)
|
||||
mw->checkForFirmwareUpdate();
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::on_fw_dnld_clicked()
|
||||
{
|
||||
MainWindow * mw = qobject_cast<MainWindow *>(this->parent());
|
||||
if (mw)
|
||||
mw->dowloadLastFirmwareUpdate();
|
||||
}
|
||||
|
||||
void FirmwarePreferencesDialog::on_sd_dnld_clicked()
|
||||
{
|
||||
QString url = g.openTxCurrentDownloadBranchUrl() % QStringLiteral("sdcard/");
|
||||
QString fwType = g.profile[g.id()].fwType();
|
||||
QStringList list = fwType.split("-");
|
||||
QString firmware = QString("%1-%2").arg(list[0]).arg(list[1]);
|
||||
if (g.boundedOpenTxBranch() != AppData::BRANCH_NIGHTLY_UNSTABLE) {
|
||||
url.append(QString("%1/").arg(firmware));
|
||||
}
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FirmwarePreferencesDialog</class>
|
||||
<widget class="QDialog" name="FirmwarePreferencesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>416</width>
|
||||
<height>154</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Downloads</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="23" column="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QPushButton" name="checkFWUpdates">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check for updates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Firmware</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QPushButton" name="fw_dnld">
|
||||
<property name="text">
|
||||
<string>Download firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="22" column="0" colspan="4">
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="3">
|
||||
<widget class="QPushButton" name="sd_dnld">
|
||||
<property name="text">
|
||||
<string>Download SD contents</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLabel" name="lastRevisionLbl">
|
||||
<property name="text">
|
||||
<string notr="true">-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Latest Download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QLabel" name="fwTypeLbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">FwType</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>checkFWUpdates</tabstop>
|
||||
<tabstop>fw_dnld</tabstop>
|
||||
<tabstop>sd_dnld</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>FirmwarePreferencesDialog</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>345</x>
|
||||
<y>133</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>207</x>
|
||||
<y>76</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 482 B |
@@ -24,13 +24,9 @@
|
||||
#include "comparedialog.h"
|
||||
#include "logsdialog.h"
|
||||
#include "apppreferencesdialog.h"
|
||||
#include "fwpreferencesdialog.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "downloaddialog.h"
|
||||
#include "printdialog.h"
|
||||
#include "version.h"
|
||||
#include "releasenotesdialog.h"
|
||||
#include "releasenotesfirmwaredialog.h"
|
||||
#include "customizesplashdialog.h"
|
||||
#include "flasheepromdialog.h"
|
||||
#include "flashfirmwaredialog.h"
|
||||
@@ -49,51 +45,22 @@
|
||||
#include "dialogs/filesyncdialog.h"
|
||||
#include "profilechooser.h"
|
||||
#include "constants.h"
|
||||
#include "updates/updates.h"
|
||||
#include "updates/updateinterface.h"
|
||||
|
||||
#include <QtGui>
|
||||
#include <QFileInfo>
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkProxyFactory>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
// update check flags
|
||||
#define CHECK_COMPANION 1
|
||||
#define CHECK_FIRMWARE 2
|
||||
#define INTERACTIVE_DOWNLOAD 4
|
||||
#define AUTOMATIC_DOWNLOAD 8
|
||||
|
||||
#define EDGETX_DOWNLOADS_PAGE_URL QStringLiteral("https://edgetx.org/downloads")
|
||||
#define DONATE_STR QStringLiteral("https://opencollective.com/edgetx/donate")
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
#define COMPANION_STAMP QStringLiteral("companion-macosx.stamp")
|
||||
#define COMPANION_INSTALLER QStringLiteral("macosx/opentx-companion-%1.dmg")
|
||||
#define COMPANION_FILEMASK QT_TRANSLATE_NOOP("MainWindow", "Diskimage (*.dmg)")
|
||||
#define COMPANION_INSTALL_QUESTION QT_TRANSLATE_NOOP("MainWindow", "Would you like to open the disk image to install the new version?")
|
||||
#elif defined(Q_OS_WIN)
|
||||
#define COMPANION_STAMP QStringLiteral("companion-windows.stamp")
|
||||
#define COMPANION_INSTALLER QStringLiteral("windows/companion-windows-%1.exe")
|
||||
#define COMPANION_FILEMASK QT_TRANSLATE_NOOP("MainWindow", "Executable (*.exe)")
|
||||
#define COMPANION_INSTALL_QUESTION QT_TRANSLATE_NOOP("MainWindow", "Would you like to launch the installer?")
|
||||
#else
|
||||
#define COMPANION_STAMP QStringLiteral("companion-linux.stamp")
|
||||
#define COMPANION_INSTALLER "" // no automated updates for linux
|
||||
#define COMPANION_FILEMASK QStringLiteral("*.*")
|
||||
#define COMPANION_INSTALL_QUESTION QT_TRANSLATE_NOOP("MainWindow", "Would you like to launch the installer?")
|
||||
#endif
|
||||
|
||||
MainWindow::MainWindow():
|
||||
downloadDialog_forWait(nullptr),
|
||||
checkForUpdatesState(0),
|
||||
networkManager(nullptr),
|
||||
updateFactories(nullptr),
|
||||
windowsListActions(new QActionGroup(this))
|
||||
{
|
||||
// setUnifiedTitleAndToolBarOnMac(true);
|
||||
this->setWindowIcon(QIcon(":/icon.png"));
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
setAcceptDrops(true);
|
||||
|
||||
mdiArea = new QMdiArea(this);
|
||||
@@ -179,8 +146,10 @@ MainWindow::MainWindow():
|
||||
QTimer::singleShot(0, this, SLOT(autoClose()));
|
||||
}
|
||||
|
||||
updateFactories = new UpdateFactories(this);
|
||||
|
||||
if (checkProfileRadioExists(g.sessionId()))
|
||||
QTimer::singleShot(updateDelay, this, SLOT(doAutoUpdates()));
|
||||
QTimer::singleShot(updateDelay, this, &MainWindow::autoUpdates);
|
||||
else
|
||||
g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE);
|
||||
}
|
||||
@@ -191,6 +160,11 @@ MainWindow::~MainWindow()
|
||||
delete windowsListActions;
|
||||
windowsListActions = nullptr;
|
||||
}
|
||||
|
||||
if (updateFactories) {
|
||||
delete updateFactories;
|
||||
updateFactories = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::initWindowOptions()
|
||||
@@ -221,388 +195,6 @@ void MainWindow::displayWarnings()
|
||||
displayWarnings(); // in case more warnings need showing
|
||||
}
|
||||
|
||||
void MainWindow::doAutoUpdates()
|
||||
{
|
||||
if (g.autoCheckApp())
|
||||
checkForUpdatesState |= CHECK_COMPANION;
|
||||
if (g.autoCheckFw())
|
||||
checkForUpdatesState |= CHECK_FIRMWARE;
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
void MainWindow::doUpdates()
|
||||
{
|
||||
checkForUpdatesState = CHECK_COMPANION | CHECK_FIRMWARE | INTERACTIVE_DOWNLOAD;
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
void MainWindow::checkForFirmwareUpdate()
|
||||
{
|
||||
checkForUpdatesState = CHECK_FIRMWARE | INTERACTIVE_DOWNLOAD;
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
void MainWindow::dowloadLastFirmwareUpdate()
|
||||
{
|
||||
checkForUpdatesState = CHECK_FIRMWARE | AUTOMATIC_DOWNLOAD | INTERACTIVE_DOWNLOAD;
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
QString MainWindow::getCompanionUpdateBaseUrl() const
|
||||
{
|
||||
return g.openTxCurrentDownloadBranchUrl() % QStringLiteral("companion/");
|
||||
}
|
||||
|
||||
void MainWindow::checkForUpdates()
|
||||
{
|
||||
if (!(checkForUpdatesState & (CHECK_COMPANION | CHECK_FIRMWARE))) {
|
||||
if (networkManager) {
|
||||
networkManager->deleteLater();
|
||||
networkManager = nullptr;
|
||||
}
|
||||
checkForUpdatesState = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("Updates via Companion currently unavailable. Please go to the EdgeTX <a href='%1'>website</a> for installation instructions. Update the application settings to disable this message.").arg("https://github.com/EdgeTX/edgetx.github.io/wiki/EdgeTX-Installation-Guide"));
|
||||
return;
|
||||
|
||||
if (networkManager)
|
||||
disconnect(networkManager, 0, this, 0);
|
||||
else
|
||||
networkManager = new QNetworkAccessManager(this);
|
||||
|
||||
QUrl url;
|
||||
if (checkForUpdatesState & CHECK_COMPANION) {
|
||||
checkForUpdatesState -= CHECK_COMPANION;
|
||||
if (checkForUpdatesState & INTERACTIVE_DOWNLOAD)
|
||||
openUpdatesWaitDialog();
|
||||
url.setUrl(getCompanionUpdateBaseUrl() % COMPANION_STAMP);
|
||||
connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::checkForCompanionUpdateFinished);
|
||||
qDebug() << "Checking for Companion update " << url.url();
|
||||
}
|
||||
else if (checkForUpdatesState & CHECK_FIRMWARE) {
|
||||
checkForUpdatesState -= CHECK_FIRMWARE;
|
||||
const QString stamp = getCurrentFirmware()->getStampUrl();
|
||||
if (!stamp.isEmpty()) {
|
||||
if (checkForUpdatesState & INTERACTIVE_DOWNLOAD)
|
||||
openUpdatesWaitDialog();
|
||||
url.setUrl(stamp);
|
||||
connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::checkForFirmwareUpdateFinished);
|
||||
qDebug() << "Checking for firmware update " << url.url();
|
||||
}
|
||||
}
|
||||
if (!url.isValid()) {
|
||||
checkForUpdates();
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||
QNetworkReply * repl = networkManager->get(request);
|
||||
if (downloadDialog_forWait)
|
||||
connect(downloadDialog_forWait, &DownloadDialog::rejected, repl, &QNetworkReply::abort);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdatesError(const QString &err)
|
||||
{
|
||||
QMessageBox::warning(this, CPN_STR_APP_NAME, err);
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
void MainWindow::openUpdatesWaitDialog()
|
||||
{
|
||||
if (!downloadDialog_forWait) {
|
||||
downloadDialog_forWait = new DownloadDialog(nullptr, tr("Checking for updates"));
|
||||
downloadDialog_forWait->show();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeUpdatesWaitDialog()
|
||||
{
|
||||
if (downloadDialog_forWait) {
|
||||
downloadDialog_forWait->close();
|
||||
delete downloadDialog_forWait;
|
||||
downloadDialog_forWait = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QString MainWindow::seekCodeString(const QByteArray & qba, const QString & label) const
|
||||
{
|
||||
int posLabel = qba.indexOf(label);
|
||||
if (posLabel < 0)
|
||||
return QString();
|
||||
int start = qba.indexOf("\"", posLabel + label.length());
|
||||
if (start < 0)
|
||||
return QString();
|
||||
int end = qba.indexOf("\"", start + 1);
|
||||
if (end < 0)
|
||||
return QString();
|
||||
return qba.mid(start + 1, end - start - 1);
|
||||
}
|
||||
|
||||
void MainWindow::checkForCompanionUpdateFinished(QNetworkReply * reply)
|
||||
{
|
||||
QByteArray qba = reply->readAll();
|
||||
reply->deleteLater();
|
||||
closeUpdatesWaitDialog();
|
||||
|
||||
QString version = seekCodeString(qba, "VERSION");
|
||||
const QString errorString = seekCodeString(qba, "ERROR");
|
||||
|
||||
if (errorString == "NO_RC")
|
||||
return onUpdatesError(tr("No Companion release candidates are currently being served for this version, please switch release channel"));
|
||||
else if (errorString == "NO_NIGHTLY")
|
||||
return onUpdatesError(tr("No nightly Companion builds are currently being served for this version, please switch release channel"));
|
||||
else if (errorString == "NO_RELEASE")
|
||||
return onUpdatesError(tr("No Companion release builds are currently being served for this version, please switch release channel"));
|
||||
|
||||
if (version.isNull())
|
||||
return onUpdatesError(tr("Companion update check failed, new version information not found."));
|
||||
|
||||
int webVersion = version2index(version);
|
||||
int ownVersion = version2index(VERSION);
|
||||
|
||||
if (ownVersion < webVersion) {
|
||||
#if defined WIN32 || defined __APPLE__
|
||||
int ret = QMessageBox::question(this, CPN_STR_APP_NAME, tr("A new version of Companion is available (version %1)<br>"
|
||||
"Would you like to download it?").arg(version) ,
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (ret == QMessageBox::Yes) {
|
||||
QDir dir(g.updatesDir());
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), dir.absoluteFilePath(QString(COMPANION_INSTALLER).arg(version)), tr(COMPANION_FILEMASK));
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
g.updatesDir(QFileInfo(fileName).dir().absolutePath());
|
||||
DownloadDialog * dd = new DownloadDialog(this, getCompanionUpdateBaseUrl() % QString(COMPANION_INSTALLER).arg(version), fileName);
|
||||
installer_fileName = fileName;
|
||||
connect(dd, SIGNAL(accepted()), this, SLOT(updateDownloaded()));
|
||||
dd->exec();
|
||||
}
|
||||
}
|
||||
#else
|
||||
QMessageBox::warning(this, tr("New release available"), tr("A new release of Companion is available, please check the <a href='%1'>EdgeTX website!</a>").arg(EDGETX_DOWNLOADS_PAGE_URL));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (checkForUpdatesState == INTERACTIVE_DOWNLOAD) {
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("No updates available at this time."));
|
||||
}
|
||||
}
|
||||
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
void MainWindow::updateDownloaded()
|
||||
{
|
||||
int ret = QMessageBox::question(this, CPN_STR_APP_NAME, tr(COMPANION_INSTALL_QUESTION), QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::Yes) {
|
||||
if (QDesktopServices::openUrl(QUrl::fromLocalFile(installer_fileName)))
|
||||
QApplication::exit();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::firmwareDownloadAccepted()
|
||||
{
|
||||
QString errormsg;
|
||||
QFile file(g.profile[g.id()].fwName());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //reading HEX TEXT file
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR,
|
||||
tr("Error opening file %1:\n%2.")
|
||||
.arg(g.profile[g.id()].fwName())
|
||||
.arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
file.reset();
|
||||
QTextStream inputStream(&file);
|
||||
QString hline = inputStream.readLine();
|
||||
if (hline.startsWith("ERROR:")) {
|
||||
int errnum = hline.mid(6).toInt();
|
||||
switch(errnum) {
|
||||
case 1:
|
||||
errormsg = tr("Not enough flash available on this board for all the selected options");
|
||||
break;
|
||||
case 2:
|
||||
errormsg = tr("Compilation server temporary failure, try later");
|
||||
break;
|
||||
case 3:
|
||||
errormsg = tr("Compilation server too busy, try later");
|
||||
break;
|
||||
case 4:
|
||||
errormsg = tr("Compilation error");
|
||||
break;
|
||||
case 5:
|
||||
errormsg = tr("Invalid firmware");
|
||||
break;
|
||||
case 6:
|
||||
errormsg = tr("Invalid board");
|
||||
break;
|
||||
case 7:
|
||||
errormsg = tr("Invalid language");
|
||||
break;
|
||||
default:
|
||||
errormsg = tr("Unknown server failure, try later");
|
||||
break;
|
||||
}
|
||||
file.close();
|
||||
file.remove();
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, errormsg);
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
g.fwRev.set(Firmware::getCurrentVariant()->getId(), version2index(firmwareVersionString));
|
||||
if (g.profile[g.id()].burnFirmware()) {
|
||||
int ret = QMessageBox::question(this, CPN_STR_APP_NAME, tr("Do you want to write the firmware to the radio now ?"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::Yes) {
|
||||
writeFlash(g.profile[g.id()].fwName());
|
||||
}
|
||||
}
|
||||
emit firmwareDownloadCompleted();
|
||||
}
|
||||
|
||||
void MainWindow::checkForFirmwareUpdateFinished(QNetworkReply * reply)
|
||||
{
|
||||
bool download = false;
|
||||
bool ignore = false;
|
||||
|
||||
const QByteArray qba = reply->readAll();
|
||||
reply->deleteLater();
|
||||
closeUpdatesWaitDialog();
|
||||
|
||||
const QString versionString = seekCodeString(qba, "VERSION");
|
||||
const QString dateString = seekCodeString(qba, "DATE");
|
||||
const QString errorString = seekCodeString(qba, "ERROR");
|
||||
const QString blockedRadios = seekCodeString(qba, "BLOCK");
|
||||
long version;
|
||||
|
||||
if (errorString == "NO_RC")
|
||||
return onUpdatesError(tr("No firmware release candidates are currently being served for this version, please switch release channel"));
|
||||
else if (errorString == "NO_NIGHTLY")
|
||||
return onUpdatesError(tr("No firmware nightly builds are currently being served for this version, please switch release channel"));
|
||||
else if (errorString == "NO_RELEASE")
|
||||
return onUpdatesError(tr("No firmware release builds are currently being served for this version, please switch release channel"));
|
||||
else if (errorString == "MOVE_TO_RC") {
|
||||
QMessageBox msgbox;
|
||||
msgbox.setIcon(QMessageBox::Question);
|
||||
msgbox.setText(tr("Release candidate builds are now available for this version, would you like to switch to using them?"));
|
||||
msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgbox.setDefaultButton(QMessageBox::Yes);
|
||||
|
||||
if(msgbox.exec() == QMessageBox::Yes) {
|
||||
g.OpenTxBranch(AppData::DownloadBranchType(AppData::BRANCH_RC_TESTING));
|
||||
return onUpdatesError(tr("Channel changed to RC, please restart the download process"));
|
||||
}
|
||||
}
|
||||
else if (errorString == "MOVE_TO_RELEASE") {
|
||||
QMessageBox msgbox;
|
||||
msgbox.setIcon(QMessageBox::Question);
|
||||
msgbox.setText(tr("Official release builds are now available for this version, would you like to switch to using them?"));
|
||||
msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgbox.setDefaultButton(QMessageBox::Yes);
|
||||
|
||||
if(msgbox.exec() == QMessageBox::Yes) {
|
||||
g.OpenTxBranch(AppData::DownloadBranchType(AppData::BRANCH_RELEASE_STABLE));
|
||||
return onUpdatesError(tr("Channel changed to Release, please restart the download process"));
|
||||
}
|
||||
}
|
||||
|
||||
QString variant = Firmware::getCurrentVariant()->getId();
|
||||
QStringList splitId = variant.split("-");
|
||||
if (blockedRadios.contains(splitId.value(1)))
|
||||
return onUpdatesError(tr("This radio (%1) is not currently available in this firmware release channel").arg(getCurrentFirmware()->getName()));
|
||||
|
||||
if (versionString.isNull() || dateString.isNull() || (version = version2index(versionString)) <= 0)
|
||||
return onUpdatesError(tr("Firmware update check failed, new version information not found or invalid."));
|
||||
|
||||
QString fullVersionString = QString("%1 (%2)").arg(versionString).arg(dateString);
|
||||
|
||||
if (checkForUpdatesState & AUTOMATIC_DOWNLOAD) {
|
||||
checkForUpdatesState -= AUTOMATIC_DOWNLOAD;
|
||||
download = true;
|
||||
}
|
||||
else {
|
||||
int currentVersion = g.fwRev.get(Firmware::getCurrentVariant()->getId());
|
||||
QString currentVersionString = index2version(currentVersion);
|
||||
|
||||
QString msgText;
|
||||
if (currentVersion == 0)
|
||||
msgText = tr("Firmware %1 does not seem to have ever been downloaded.\nVersion %2 is available.\nDo you want to download it now?\n\nWe recommend you view the release notes using the button below to learn about any changes that may be important to you.")
|
||||
.arg(Firmware::getCurrentVariant()->getId()).arg(fullVersionString);
|
||||
else if (version > currentVersion)
|
||||
msgText = tr("A new version of %1 firmware is available:\n - current is %2\n - newer is %3\n\nDo you want to download it now?\n\nWe recommend you view the release notes using the button below to learn about any changes that may be important to you.")
|
||||
.arg(Firmware::getCurrentVariant()->getId()).arg(currentVersionString).arg(fullVersionString);
|
||||
else if (checkForUpdatesState == INTERACTIVE_DOWNLOAD)
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("No updates available at this time."));
|
||||
|
||||
if (currentVersion == 0 || version > currentVersion) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(CPN_STR_APP_NAME);
|
||||
QSpacerItem * horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QGridLayout * layout = (QGridLayout*)msgBox.layout();
|
||||
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
|
||||
|
||||
QString rn = getCurrentFirmware()->getReleaseNotesUrl();
|
||||
QAbstractButton *rnButton = nullptr;
|
||||
msgBox.setText(msgText);
|
||||
QAbstractButton *YesButton = msgBox.addButton(tr("Yes"), QMessageBox::YesRole);
|
||||
msgBox.addButton(tr("No"), QMessageBox::NoRole);
|
||||
if (!rn.isEmpty()) {
|
||||
rnButton = msgBox.addButton(tr("Release Notes"), QMessageBox::ActionRole);
|
||||
}
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.resize(0, 0);
|
||||
msgBox.exec();
|
||||
if (msgBox.clickedButton() == rnButton) {
|
||||
QDesktopServices::openUrl(QUrl(rn));
|
||||
int ret2 = QMessageBox::question(this, CPN_STR_APP_NAME, tr("Do you want to download version %1 now ?").arg(fullVersionString), QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret2 == QMessageBox::Yes)
|
||||
download = true;
|
||||
else
|
||||
ignore = true;
|
||||
}
|
||||
else if (msgBox.clickedButton() == YesButton )
|
||||
download = true;
|
||||
else
|
||||
ignore = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore) {
|
||||
int res = QMessageBox::question(this, CPN_STR_APP_NAME, tr("Ignore this version %1?").arg(fullVersionString), QMessageBox::Yes | QMessageBox::No);
|
||||
if (res==QMessageBox::Yes) {
|
||||
g.fwRev.set(Firmware::getCurrentVariant()->getId(), version);
|
||||
}
|
||||
}
|
||||
else if (download == true) {
|
||||
firmwareVersionString = versionString;
|
||||
startFirmwareDownload();
|
||||
}
|
||||
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
void MainWindow::startFirmwareDownload()
|
||||
{
|
||||
QString url = Firmware::getCurrentVariant()->getFirmwareUrl();
|
||||
qDebug() << "Downloading firmware" << url;
|
||||
QString ext = url.mid(url.lastIndexOf("."));
|
||||
QString defaultFilename = g.flashDir() + "/" + Firmware::getCurrentVariant()->getId();
|
||||
if (g.profile[g.id()].renameFwFiles()) {
|
||||
defaultFilename += "-" + firmwareVersionString;
|
||||
}
|
||||
defaultFilename += ext;
|
||||
|
||||
QString filename = QFileDialog::getSaveFileName(this, tr("Save As"), defaultFilename);
|
||||
if (!filename.isEmpty()) {
|
||||
g.profile[g.id()].fwName(filename);
|
||||
g.flashDir(QFileInfo(filename).dir().absolutePath());
|
||||
DownloadDialog * dd = new DownloadDialog(this, url, filename);
|
||||
connect(dd, SIGNAL(accepted()), this, SLOT(firmwareDownloadAccepted()));
|
||||
dd->exec();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
g.mainWinGeo(saveGeometry());
|
||||
@@ -643,6 +235,20 @@ void MainWindow::onLanguageChanged(QAction * act)
|
||||
setLanguage(lang);
|
||||
}
|
||||
|
||||
void MainWindow::autoUpdates()
|
||||
{
|
||||
Updates *upd = new Updates(this, updateFactories);
|
||||
upd->autoUpdates();
|
||||
delete upd;
|
||||
}
|
||||
|
||||
void MainWindow::manualUpdates()
|
||||
{
|
||||
Updates *upd = new Updates(this, updateFactories);
|
||||
upd->manualUpdates();
|
||||
delete upd;
|
||||
}
|
||||
|
||||
void MainWindow::setTheme(int index)
|
||||
{
|
||||
g.theme(index);
|
||||
@@ -825,7 +431,7 @@ void MainWindow::loadProfile()
|
||||
|
||||
void MainWindow::appPrefs()
|
||||
{
|
||||
AppPreferencesDialog * dialog = new AppPreferencesDialog(this);
|
||||
AppPreferencesDialog * dialog = new AppPreferencesDialog(this, updateFactories);
|
||||
dialog->setMainWinHasDirtyChild(anyChildrenDirty());
|
||||
connect(dialog, &AppPreferencesDialog::firmwareProfileAboutToChange, this, &MainWindow::saveAll);
|
||||
connect(dialog, &AppPreferencesDialog::firmwareProfileChanged, this, &MainWindow::onCurrentProfileChanged);
|
||||
@@ -833,13 +439,6 @@ void MainWindow::appPrefs()
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::fwPrefs()
|
||||
{
|
||||
FirmwarePreferencesDialog * dialog = new FirmwarePreferencesDialog(this);
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::sdsync()
|
||||
{
|
||||
// remember user-selectable options for duration of session TODO: save to settings
|
||||
@@ -886,7 +485,7 @@ void MainWindow::sdsync()
|
||||
|
||||
void MainWindow::changelog()
|
||||
{
|
||||
QString link = "https://edgetx.org";
|
||||
QString link = "https://github.com/EdgeTX/edgetx/releases";
|
||||
QDesktopServices::openUrl(QUrl(link));
|
||||
}
|
||||
|
||||
@@ -1191,14 +790,14 @@ void MainWindow::retranslateUi(bool showMsg)
|
||||
trAct(saveAsAct, tr("Save As..."), tr("Save Models and Settings file"));
|
||||
trAct(closeAct, tr("Close"), tr("Close Models and Settings file"));
|
||||
trAct(exitAct, tr("Exit"), tr("Exit the application"));
|
||||
trAct(aboutAct, tr("About..."), tr("Show the application's About box"));
|
||||
trAct(aboutAct, tr("About Companion..."), tr("Show the application's About box"));
|
||||
|
||||
trAct(recentFilesAct, tr("Recent Files"), tr("List of recently used files"));
|
||||
trAct(profilesMenuAct, tr("Radio Profiles"), tr("Create or Select Radio Profiles"));
|
||||
trAct(logsAct, tr("View Log File..."), tr("Open and view log file"));
|
||||
trAct(appPrefsAct, tr("Settings..."), tr("Edit Settings"));
|
||||
trAct(fwPrefsAct, tr("Download..."), tr("Download firmware and voice files"));
|
||||
trAct(checkForUpdatesAct, tr("Check for Updates..."), tr("Check EdgeTX and Companion updates"));
|
||||
trAct(updatesAct, tr("Updates..."), tr("Update EdgeTX and supporting resources"));
|
||||
trAct(checkForUpdatesAct, tr("Check for updates..."), tr("Check for updates to EdgeTX and supporting resources"));
|
||||
trAct(changelogAct, tr("Release notes..."), tr("Show release notes"));
|
||||
trAct(compareAct, tr("Compare Models..."), tr("Compare models"));
|
||||
trAct(editSplashAct, tr("Edit Radio Splash Image..."), tr("Edit the splash image of your Radio"));
|
||||
@@ -1256,7 +855,7 @@ void MainWindow::createActions()
|
||||
|
||||
logsAct = addAct("logs.png", SLOT(logFile()), tr("Ctrl+Alt+L"));
|
||||
appPrefsAct = addAct("apppreferences.png", SLOT(appPrefs()), QKeySequence::Preferences);
|
||||
fwPrefsAct = addAct("fwpreferences.png", SLOT(fwPrefs()), tr("Ctrl+Alt+D"));
|
||||
updatesAct = addAct("download.png", SLOT(manualUpdates()), tr("Ctrl+Alt+D"));
|
||||
compareAct = addAct("compare.png", SLOT(compare()), tr("Ctrl+Alt+R"));
|
||||
sdsyncAct = addAct("sdsync.png", SLOT(sdsync()));
|
||||
|
||||
@@ -1283,7 +882,7 @@ void MainWindow::createActions()
|
||||
actCascadeWindows = addAct("", SLOT(cascadeSubWindows()), 0, mdiArea);
|
||||
actCloseAllWindows = addAct("", SLOT(closeAllSubWindows()), 0, mdiArea);
|
||||
|
||||
checkForUpdatesAct = addAct("update.png", SLOT(doUpdates()));
|
||||
checkForUpdatesAct = addAct("update.png", SLOT(autoUpdates()));
|
||||
aboutAct = addAct("information.png", SLOT(about()));
|
||||
openDocURLAct = addAct("changelog.png", SLOT(openDocURL()));
|
||||
changelogAct = addAct("changelog.png", SLOT(changelog()));
|
||||
@@ -1301,7 +900,6 @@ void MainWindow::createActions()
|
||||
|
||||
actTabbedWindows->setCheckable(true);
|
||||
compareAct->setEnabled(false);
|
||||
fwPrefsAct->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::createMenus()
|
||||
@@ -1315,7 +913,7 @@ void MainWindow::createMenus()
|
||||
fileMenu->addAction(recentFilesAct);
|
||||
fileMenu->addSeparator();
|
||||
fileMenu->addAction(logsAct);
|
||||
fileMenu->addAction(fwPrefsAct);
|
||||
fileMenu->addAction(updatesAct);
|
||||
fileMenu->addAction(compareAct);
|
||||
fileMenu->addAction(sdsyncAct);
|
||||
fileMenu->addSeparator();
|
||||
@@ -1374,14 +972,13 @@ void MainWindow::createMenus()
|
||||
windowMenu->addSeparator();
|
||||
|
||||
helpMenu = menuBar()->addMenu("");
|
||||
helpMenu->addSeparator();
|
||||
helpMenu->addAction(checkForUpdatesAct);
|
||||
helpMenu->addSeparator();
|
||||
helpMenu->addAction(aboutAct);
|
||||
helpMenu->addAction(openDocURLAct);
|
||||
helpMenu->addSeparator();
|
||||
//helpMenu->addSeparator();
|
||||
//helpMenu->addAction(openDocURLAct);
|
||||
//helpMenu->addSeparator();
|
||||
helpMenu->addAction(changelogAct);
|
||||
helpMenu->addSeparator();
|
||||
//helpMenu->addSeparator();
|
||||
helpMenu->addAction(aboutAct);
|
||||
|
||||
recentFilesMenu = new QMenu(this);
|
||||
recentFilesMenu->setToolTipsVisible(true);
|
||||
@@ -1419,7 +1016,7 @@ void MainWindow::createToolBars()
|
||||
fileToolBar->addAction(closeAct);
|
||||
fileToolBar->addSeparator();
|
||||
fileToolBar->addAction(logsAct);
|
||||
fileToolBar->addAction(fwPrefsAct);
|
||||
fileToolBar->addAction(updatesAct);
|
||||
fileToolBar->addSeparator();
|
||||
fileToolBar->addAction(appPrefsAct);
|
||||
fileToolBar->addAction(profilesMenuAct);
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MAINWINDOW_H_
|
||||
#define _MAINWINDOW_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QDateTime>
|
||||
#include "downloaddialog.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
#define SPLASH_TIME 5
|
||||
|
||||
class MdiChild;
|
||||
class UpdateFactories;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QMenu;
|
||||
@@ -47,18 +47,11 @@ class MainWindow : public QMainWindow
|
||||
~MainWindow();
|
||||
|
||||
signals:
|
||||
void firmwareDownloadCompleted();
|
||||
void firmwareChanged();
|
||||
void startSync();
|
||||
void onInternalModuleChanged();
|
||||
|
||||
protected:
|
||||
QString getCompanionUpdateBaseUrl() const;
|
||||
QString seekCodeString(const QByteArray & qba, const QString & label) const;
|
||||
|
||||
protected slots:
|
||||
void dowloadLastFirmwareUpdate();
|
||||
void startFirmwareDownload();
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
virtual void changeEvent(QEvent *e);
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
@@ -83,17 +76,7 @@ class MainWindow : public QMainWindow
|
||||
void onSubwindowModified();
|
||||
void onCurrentProfileChanged();
|
||||
|
||||
void checkForUpdates();
|
||||
void checkForFirmwareUpdate();
|
||||
|
||||
void checkForCompanionUpdateFinished(QNetworkReply * reply);
|
||||
void checkForFirmwareUpdateFinished(QNetworkReply * reply);
|
||||
|
||||
void displayWarnings();
|
||||
void doAutoUpdates();
|
||||
void doUpdates();
|
||||
void updateDownloaded();
|
||||
void firmwareDownloadAccepted();
|
||||
void newFile();
|
||||
void openFile();
|
||||
void save();
|
||||
@@ -118,7 +101,6 @@ class MainWindow : public QMainWindow
|
||||
void about();
|
||||
void compare();
|
||||
void appPrefs();
|
||||
void fwPrefs();
|
||||
void updateMenus();
|
||||
void createProfile();
|
||||
void copyProfile();
|
||||
@@ -128,10 +110,9 @@ class MainWindow : public QMainWindow
|
||||
void importSettings();
|
||||
void autoClose();
|
||||
void chooseProfile();
|
||||
void manualUpdates();
|
||||
void autoUpdates();
|
||||
|
||||
void openUpdatesWaitDialog();
|
||||
void closeUpdatesWaitDialog();
|
||||
void onUpdatesError(const QString & err);
|
||||
void openFile(const QString & fileName, bool updateLastUsedDir = false);
|
||||
|
||||
private:
|
||||
@@ -165,11 +146,7 @@ class MainWindow : public QMainWindow
|
||||
QMdiArea *mdiArea;
|
||||
|
||||
QString installer_fileName;
|
||||
DownloadDialog * downloadDialog_forWait;
|
||||
unsigned int checkForUpdatesState;
|
||||
QString firmwareVersionString;
|
||||
|
||||
QNetworkAccessManager *networkManager;
|
||||
UpdateFactories *updateFactories;
|
||||
|
||||
QVector<QAction *> recentFileActs;
|
||||
QVector<QAction *> profileActs;
|
||||
@@ -198,7 +175,7 @@ class MainWindow : public QMainWindow
|
||||
QAction *recentFilesAct;
|
||||
QAction *exitAct;
|
||||
QAction *appPrefsAct;
|
||||
QAction *fwPrefsAct;
|
||||
QAction *updatesAct;
|
||||
QAction *checkForUpdatesAct;
|
||||
QAction *sdsyncAct;
|
||||
QAction *changelogAct;
|
||||
@@ -226,5 +203,3 @@ class MainWindow : public QMainWindow
|
||||
QAction *actCascadeWindows;
|
||||
QAction *actCloseAllWindows;
|
||||
};
|
||||
|
||||
#endif // _MAINWINDOW_H_
|
||||
|
||||
@@ -18,15 +18,10 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _PROGRESSWIDGET_H_
|
||||
#define _PROGRESSWIDGET_H_
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
|
||||
#define QtInfoMsg QtMsgType(4)
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class ProgressWidget;
|
||||
}
|
||||
@@ -71,5 +66,3 @@ class ProgressWidget : public QWidget
|
||||
bool m_forceOpen;
|
||||
bool m_hasDetails;
|
||||
};
|
||||
|
||||
#endif // _PROGRESSWIDGET_H_
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
@@ -86,6 +91,11 @@
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* 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 "releasenotesfirmwaredialog.h"
|
||||
#include "ui_htmldialog.h"
|
||||
#include "helpers.h"
|
||||
|
||||
ReleaseNotesFirmwareDialog::ReleaseNotesFirmwareDialog(QWidget * parent, const QString & rnurl):
|
||||
QDialog(parent),
|
||||
ui(new Ui::HtmlDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowTitle(tr("OpenTX Release Notes"));
|
||||
setWindowIcon(CompanionIcon("changelog.png"));
|
||||
|
||||
manager = new QNetworkAccessManager(this);
|
||||
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
|
||||
QUrl url(rnurl);
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||
manager->get(request);
|
||||
}
|
||||
|
||||
ReleaseNotesFirmwareDialog::~ReleaseNotesFirmwareDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ReleaseNotesFirmwareDialog::replyFinished(QNetworkReply * reply)
|
||||
{
|
||||
ui->textEditor->setHtml(reply->readAll());
|
||||
ui->textEditor->setOpenExternalLinks(true);
|
||||
reply->deleteLater();
|
||||
}
|
||||
@@ -16,6 +16,7 @@ set(storage_NAMES
|
||||
otx
|
||||
yaml
|
||||
crc
|
||||
minizinterface
|
||||
)
|
||||
|
||||
set(storage_SRCS
|
||||
|
||||
@@ -289,6 +289,42 @@ void Profile::resetFwVariables()
|
||||
}
|
||||
|
||||
|
||||
// ** ComponentData class********************
|
||||
|
||||
ComponentData::ComponentData() : CompStoreObj(), index(-1)
|
||||
{
|
||||
qRegisterMetaTypeStreamOperators<ComponentData::ReleaseChannel>("ComponentData::ReleaseChannel");
|
||||
CompStoreObj::addObjectMapping(propertyGroup(), this);
|
||||
}
|
||||
|
||||
// The default copy operator can not be used since the index variable would be destroyed
|
||||
ComponentData & ComponentData::operator= (const ComponentData & rhs)
|
||||
{
|
||||
for (int i = metaObject()->propertyOffset(), e = metaObject()->propertyCount(); i < e; ++i) {
|
||||
const QMetaProperty & prop = metaObject()->property(i);
|
||||
if (!prop.isValid() || !prop.isWritable()) {
|
||||
qWarning() << "Could not copy property" << QString(prop.name()) << "isValid:" << prop.isValid() << "isWritable:" << prop.isWritable();
|
||||
continue;
|
||||
}
|
||||
prop.write(this, prop.read(&rhs));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ComponentData::existsOnDisk()
|
||||
{
|
||||
return (m_settings.contains(settingsPath() % "name"));
|
||||
}
|
||||
|
||||
void ComponentData::clearRelease()
|
||||
{
|
||||
release(CompStoreObj::propertyDefaultValue(this, "release").toString());
|
||||
id(CompStoreObj::propertyDefaultValue(this, "id").toInt());
|
||||
prerelease(CompStoreObj::propertyDefaultValue(this, "prerelease").toBool());
|
||||
date(CompStoreObj::propertyDefaultValue(this, "date").toString());
|
||||
version(CompStoreObj::propertyDefaultValue(this, "version").toString());
|
||||
}
|
||||
|
||||
// ** AppData class********************
|
||||
|
||||
AppData::AppData() :
|
||||
@@ -297,8 +333,8 @@ AppData::AppData() :
|
||||
{
|
||||
QMetaType::registerComparators<SimulatorOptions>();
|
||||
qRegisterMetaTypeStreamOperators<SimulatorOptions>("SimulatorOptions");
|
||||
qRegisterMetaTypeStreamOperators<AppData::DownloadBranchType>("AppData::DownloadBranchType");
|
||||
qRegisterMetaTypeStreamOperators<AppData::NewModelAction>("AppData::NewModelAction");
|
||||
qRegisterMetaTypeStreamOperators<AppData::UpdateCheckFreq>("AppData::UpdateCheckFreq");
|
||||
|
||||
CompStoreObj::addObjectMapping(propertyGroup(), this);
|
||||
|
||||
@@ -315,6 +351,10 @@ AppData::AppData() :
|
||||
// Configure the joysticks
|
||||
for (int i=0; i<MAX_JOYSTICKS; i++)
|
||||
joystick[i].setIndex(i);
|
||||
|
||||
// Configure the updates
|
||||
for (int i=0; i<MAX_COMPONENTS; i++)
|
||||
component[i].setIndex(i);
|
||||
}
|
||||
|
||||
static QString fmtHex(quint32 num)
|
||||
@@ -346,6 +386,9 @@ void AppData::initAll()
|
||||
// Initialize the joysticks
|
||||
for (int i=0; i<MAX_JOYSTICKS; i++)
|
||||
joystick[i].init();
|
||||
// Initialize the updatess
|
||||
for (int i=0; i<MAX_COMPONENTS; i++)
|
||||
component[i].init();
|
||||
}
|
||||
|
||||
void AppData::resetAllSettings()
|
||||
@@ -356,6 +399,8 @@ void AppData::resetAllSettings()
|
||||
profile[i].resetAll();
|
||||
for (int i=0; i<MAX_JOYSTICKS; i++)
|
||||
joystick[i].resetAll();
|
||||
for (int i=0; i<MAX_COMPONENTS; i++)
|
||||
component[i].resetAll();
|
||||
firstUse = true;
|
||||
}
|
||||
|
||||
@@ -366,6 +411,8 @@ void AppData::storeAllSettings()
|
||||
profile[i].storeAll();
|
||||
for (int i=0; i<MAX_JOYSTICKS; i++)
|
||||
joystick[i].storeAll();
|
||||
for (int i=0; i<MAX_COMPONENTS; i++)
|
||||
component[i].storeAll();
|
||||
}
|
||||
|
||||
bool AppData::hasCurrentSettings() const
|
||||
@@ -406,6 +453,15 @@ QMap<int, QString> AppData::getActiveProfiles() const
|
||||
return active;
|
||||
}
|
||||
|
||||
int AppData::getComponentIndex(QString name) const
|
||||
{
|
||||
for (int i=0; i<MAX_COMPONENTS; i++) {
|
||||
if (g.component[i].existsOnDisk() && g.component[i].name() == name)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AppData::convertSettings(QSettings & settings)
|
||||
{
|
||||
quint32 savedVer = settings.value(SETTINGS_VERSION_KEY, 0).toUInt();
|
||||
@@ -580,3 +636,27 @@ bool AppData::exportSettingsToFile(const QString & expFile, QString & resultMsg)
|
||||
resultMsg.append(tr("for unknown reasons."));
|
||||
return false;
|
||||
}
|
||||
|
||||
ComponentData & AppData::getComponent(int index)
|
||||
{
|
||||
if (index > -1 && index < MAX_COMPONENTS)
|
||||
return component[index];
|
||||
return component[0];
|
||||
}
|
||||
|
||||
const ComponentData & AppData::getComponent(int index) const
|
||||
{
|
||||
if (index > -1 && index < MAX_COMPONENTS)
|
||||
return component[index];
|
||||
return component[0];
|
||||
}
|
||||
|
||||
void AppData::resetUpdatesSettings()
|
||||
{
|
||||
g.updateCheckFreqReset();
|
||||
g.downloadDirReset();
|
||||
g.decompressDirReset();
|
||||
g.decompressUseDwnldReset();
|
||||
g.updateDirReset();
|
||||
g.updateUseSDReset();
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef _APPDATA_H_
|
||||
#define _APPDATA_H_
|
||||
#pragma once
|
||||
|
||||
#include "constants.h"
|
||||
#include "macros.h"
|
||||
@@ -59,14 +58,9 @@
|
||||
#define CPN_SETTINGS_INI_FILE QString(PRODUCT % " " % QCoreApplication::translate("Companion", "settings") % " %1.ini")
|
||||
#define CPN_SETTINGS_INI_PATH QString(CPN_SETTINGS_BACKUP_DIR % "/" % CPN_SETTINGS_INI_FILE)
|
||||
|
||||
#define CPN_URL_DOWNLOAD "https://downloads.edgetx.org/"
|
||||
#define CPN_URL_DOWNLOAD_CUR_VERS CPN_URL_DOWNLOAD QT_STRINGIFY(VERSION_MAJOR) "." QT_STRINGIFY(VERSION_MINOR) "/"
|
||||
#define CPN_URL_DOWNLOAD_CUR_REL CPN_URL_DOWNLOAD_CUR_VERS "release/"
|
||||
#define CPN_URL_DOWNLOAD_CUR_RC CPN_URL_DOWNLOAD_CUR_VERS "rc/"
|
||||
#define CPN_URL_DOWNLOAD_CUR_UNST CPN_URL_DOWNLOAD_CUR_VERS "nightlies/"
|
||||
|
||||
#define MAX_PROFILES 20
|
||||
#define MAX_JOYSTICKS 8
|
||||
#define MAX_COMPONENTS 10
|
||||
|
||||
// It important that these function names are consistent everywhere.
|
||||
#define PROP_FSIG_INIT_IMPL _init()
|
||||
@@ -427,6 +421,51 @@ class Profile: public CompStoreObj
|
||||
}
|
||||
};
|
||||
|
||||
//! \brief ComponentData class stores properties related to each updateable component.
|
||||
class ComponentData: public CompStoreObj
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComponentData & operator=(const ComponentData & rhs);
|
||||
|
||||
enum ReleaseChannel {
|
||||
RELEASE_CHANNEL_STABLE,
|
||||
RELEASE_CHANNEL_PRERELEASE,
|
||||
RELEASE_CHANNEL_NIGHTLY
|
||||
};
|
||||
Q_ENUM(ReleaseChannel)
|
||||
|
||||
void clearRelease();
|
||||
static QStringList releaseChannelsList() { return { tr("Releases"), tr("Pre-release"), tr("Nightly") } ; }
|
||||
|
||||
inline ReleaseChannel boundedReleaseChannel() const {
|
||||
return qBound(RELEASE_CHANNEL_STABLE, releaseChannel(), RELEASE_CHANNEL_NIGHTLY);
|
||||
}
|
||||
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
|
||||
protected:
|
||||
explicit ComponentData();
|
||||
void setIndex(int idx) { index = idx; }
|
||||
inline QString propertyGroup() const override { return QStringLiteral("Components"); }
|
||||
inline QString settingsPath() const override { return QString("%1/component%2/").arg(propertyGroup()).arg(index); }
|
||||
friend class AppData;
|
||||
|
||||
private:
|
||||
PROPERTYSTR (name)
|
||||
PROPERTY (bool, checkForUpdate, false)
|
||||
PROPERTY (ReleaseChannel, releaseChannel, RELEASE_CHANNEL_STABLE)
|
||||
PROPERTYSTRD( release, "unknown")
|
||||
PROPERTY (int, id, 0)
|
||||
PROPERTY (bool, prerelease, false)
|
||||
PROPERTYSTRD( version, "0")
|
||||
PROPERTYSTRD( date, "")
|
||||
|
||||
int index;
|
||||
|
||||
CREATE_ENUM_FRIEND_STREAM_OPS(ComponentData::ReleaseChannel)
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief The AppData class acts as the main interface for all application settings.
|
||||
@@ -441,13 +480,6 @@ class AppData: public CompStoreObj
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum DownloadBranchType {
|
||||
BRANCH_RELEASE_STABLE,
|
||||
BRANCH_RC_TESTING,
|
||||
BRANCH_NIGHTLY_UNSTABLE
|
||||
};
|
||||
Q_ENUM(DownloadBranchType)
|
||||
|
||||
enum NewModelAction {
|
||||
MODEL_ACT_NONE,
|
||||
MODEL_ACT_WIZARD,
|
||||
@@ -457,13 +489,24 @@ class AppData: public CompStoreObj
|
||||
};
|
||||
Q_ENUM(NewModelAction)
|
||||
|
||||
enum UpdateCheckFreq {
|
||||
UPDATE_CHECK_MANUAL,
|
||||
UPDATE_CHECK_STARTUP,
|
||||
UPDATE_CHECK_DAILY,
|
||||
UPDATE_CHECK_WEEKLY,
|
||||
UPDATE_CHECK_MONTHLY
|
||||
};
|
||||
Q_ENUM(UpdateCheckFreq)
|
||||
|
||||
static QStringList newModelActionsList() { return { tr("None"), tr("Wizard"), tr("Editor"), tr("Template"), tr("Prompt") } ; }
|
||||
static QStringList updateCheckFreqsList() { return { tr("Manually"), tr("Startup"), tr("Daily"), tr("Weekly"), tr("Monthly") } ; }
|
||||
|
||||
explicit AppData();
|
||||
void init() override;
|
||||
void initAll();
|
||||
void resetAllSettings();
|
||||
void storeAllSettings();
|
||||
void resetUpdatesSettings();
|
||||
|
||||
inline bool isFirstUse() const { return firstUse; }
|
||||
inline QString previousVersion() const { return upgradeFromVersion; }
|
||||
@@ -487,6 +530,13 @@ class AppData: public CompStoreObj
|
||||
//! List of all active profiles mapped by index.
|
||||
QMap<int, QString> getActiveProfiles() const;
|
||||
|
||||
//! Get a modifiable (non-const) index to ComponentData for \a name. Returns -1 if \a name not found.
|
||||
int getComponentIndex(QString name) const;
|
||||
//! Get a modifiable (non-const) reference to the ComponentData at \a index. Returns component[0] if \a index is invalid.
|
||||
ComponentData & getComponent(int index);
|
||||
//! Get a non-modifiable (const) reference to the ComponentData at \a index. Returns component[0] if \a index is invalid.
|
||||
const ComponentData & getComponent(int index) const;
|
||||
|
||||
//! Find the set of settings from the last previous version installed, if any. Used at virgin startup to offer import option.
|
||||
bool findPreviousVersionSettings(QString * version) const;
|
||||
//! Converts any old/refactored settings to new ones and removes anything stale if \a removeUnused is true. This is only important when
|
||||
@@ -500,25 +550,10 @@ class AppData: public CompStoreObj
|
||||
bool exportSettings(QSettings * toSettings, bool clearDestination = true);
|
||||
bool exportSettingsToFile(const QString & expFile, QString & resultMsg);
|
||||
|
||||
inline DownloadBranchType boundedOpenTxBranch() const {
|
||||
#if defined(ALLOW_NIGHTLY_BUILDS)
|
||||
return qBound(BRANCH_RELEASE_STABLE, OpenTxBranch(), BRANCH_NIGHTLY_UNSTABLE);
|
||||
#else
|
||||
return qBound(BRANCH_RELEASE_STABLE, OpenTxBranch(), BRANCH_RC_TESTING);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline QString openTxCurrentDownloadBranchUrl() const { return openTxDownloadBranchUrl(boundedOpenTxBranch()); }
|
||||
|
||||
static const QString openTxDownloadBranchUrl(DownloadBranchType type)
|
||||
{
|
||||
static const QStringList urlList({ CPN_URL_DOWNLOAD_CUR_REL, CPN_URL_DOWNLOAD_CUR_RC, CPN_URL_DOWNLOAD_CUR_UNST });
|
||||
return urlList.value(type, CPN_URL_DOWNLOAD_CUR_VERS);
|
||||
}
|
||||
|
||||
Profile profile[MAX_PROFILES];
|
||||
JStickData joystick[MAX_JOYSTICKS];
|
||||
FwRevision fwRev;
|
||||
ComponentData component[MAX_COMPONENTS];
|
||||
|
||||
signals:
|
||||
void currentProfileChanged();
|
||||
@@ -541,47 +576,56 @@ class AppData: public CompStoreObj
|
||||
PROPERTYQBA (mdiWinState)
|
||||
PROPERTYQBA (compareWinGeo)
|
||||
|
||||
PROPERTYSTR3(armMcu, "arm_mcu", QStringLiteral("at91sam3s4-9x"))
|
||||
PROPERTYSTR3(armMcu, "arm_mcu", QStringLiteral("at91sam3s4-9x"))
|
||||
PROPERTYSTR2(avrArguments, "avr_arguments")
|
||||
PROPERTYSTR2(avrPort, "avr_port")
|
||||
PROPERTYSTR2(avrdudeLocation, "avrdudeLocation")
|
||||
PROPERTYSTR3(dfuArguments, "dfu_arguments", QStringLiteral("-a 0"))
|
||||
PROPERTYSTR3(dfuArguments, "dfu_arguments", QStringLiteral("-a 0"))
|
||||
PROPERTYSTR2(dfuLocation, "dfu_location")
|
||||
PROPERTYSTR2(sambaLocation, "samba_location")
|
||||
PROPERTYSTR3(sambaPort, "samba_port", QStringLiteral("\\USBserial\\COM23"))
|
||||
PROPERTYSTR2(backupDir, "backupPath")
|
||||
PROPERTYSTR2(eepromDir, "lastDir")
|
||||
PROPERTYSTR2(flashDir, "lastFlashDir")
|
||||
PROPERTYSTR2(imagesDir, "lastImagesDir")
|
||||
PROPERTYSTR2(logDir, "lastLogDir")
|
||||
PROPERTYSTR3(sambaPort, "samba_port", QStringLiteral("\\USBserial\\COM23"))
|
||||
|
||||
PROPERTYSTR2(libDir, "libraryPath")
|
||||
PROPERTYSTR2(snapshotDir, "snapshotpath")
|
||||
PROPERTYSTR2(updatesDir, "lastUpdatesDir")
|
||||
|
||||
PROPERTYSTR3(backupDir, "backupPath", CPN_DOCUMENTS_LOCATION % "/backups")
|
||||
PROPERTYSTR3(eepromDir, "lastDir", CPN_DOCUMENTS_LOCATION % "/eeproms")
|
||||
PROPERTYSTR3(flashDir, "lastFlashDir", CPN_DOCUMENTS_LOCATION % "/flash")
|
||||
PROPERTYSTR3(imagesDir, "lastImagesDir", CPN_DOCUMENTS_LOCATION % "/images")
|
||||
PROPERTYSTR3(logDir, "lastLogDir", CPN_DOCUMENTS_LOCATION % "/debuglogs")
|
||||
PROPERTYSTRD(appLogsDir, CPN_DOCUMENTS_LOCATION % "/debuglogs")
|
||||
PROPERTYSTR3(snapshotDir, "snapshotpath", CPN_DOCUMENTS_LOCATION % "/snapshots")
|
||||
PROPERTYSTRD(templatesDir, CPN_DOCUMENTS_LOCATION % "/templates")
|
||||
PROPERTYSTRD(downloadDir, CPN_DOCUMENTS_LOCATION % "/downloads")
|
||||
PROPERTYSTRD(decompressDir, CPN_DOCUMENTS_LOCATION % "/decompress")
|
||||
PROPERTY (bool, decompressUseDwnld, true)
|
||||
PROPERTYSTRD(updateDir, CPN_DOCUMENTS_LOCATION % "/updates")
|
||||
PROPERTY (bool, updateUseSD, true)
|
||||
PROPERTY (int, updateLogLevel, 0)
|
||||
|
||||
PROPERTYSTR (locale)
|
||||
PROPERTYSTR (gePath)
|
||||
PROPERTYSTRD(mcu, QStringLiteral("m64"))
|
||||
PROPERTYSTRD(programmer, QStringLiteral("usbasp"))
|
||||
PROPERTYSTRD(appLogsDir, CPN_DOCUMENTS_LOCATION % "/DebugLogs")
|
||||
|
||||
PROPERTY(DownloadBranchType, OpenTxBranch, BRANCH_RELEASE_STABLE)
|
||||
PROPERTY(NewModelAction, newModelAction, MODEL_ACT_WIZARD)
|
||||
PROPERTY(NewModelAction, newModelAction, MODEL_ACT_WIZARD)
|
||||
|
||||
PROPERTY4(int, embedSplashes, "embedded_splashes", 0)
|
||||
PROPERTY4(int, fwServerFails, "fwserver", 0)
|
||||
PROPERTY4(int, iconSize, "icon_size", 2)
|
||||
PROPERTY4(int, jsCtrl, "js_ctrl", 0)
|
||||
PROPERTY4(int, historySize, "history_size", 10)
|
||||
PROPERTY (int, generalEditTab, 0)
|
||||
PROPERTY (int, theme, 1)
|
||||
PROPERTY (int, warningId, 0)
|
||||
PROPERTY4(int, embedSplashes, "embedded_splashes", 0)
|
||||
PROPERTY4(int, fwServerFails, "fwserver", 0)
|
||||
PROPERTY4(int, iconSize, "icon_size", 2)
|
||||
PROPERTY4(int, jsCtrl, "js_ctrl", 0)
|
||||
PROPERTY4(int, historySize, "history_size", 10)
|
||||
PROPERTY (int, generalEditTab, 0)
|
||||
PROPERTY (int, theme, 1)
|
||||
PROPERTY (int, warningId, 0)
|
||||
|
||||
PROPERTY4(bool, jsSupport, "js_support", false)
|
||||
PROPERTY4(bool, showSplash, "show_splash", true)
|
||||
PROPERTY4(bool, snapToClpbrd, "snapshot_to_clipboard", false)
|
||||
PROPERTY4(bool, autoCheckApp, "startup_check_companion", false)
|
||||
PROPERTY4(bool, autoCheckFw, "startup_check_fw", false)
|
||||
PROPERTY4(bool, promptProfile, "startup_prompt_profile", false)
|
||||
PROPERTY4(bool, jsSupport, "js_support", false)
|
||||
PROPERTY4(bool, showSplash, "show_splash", true)
|
||||
PROPERTY4(bool, snapToClpbrd, "snapshot_to_clipboard", false)
|
||||
|
||||
PROPERTY(UpdateCheckFreq, updateCheckFreq, UPDATE_CHECK_MANUAL)
|
||||
PROPERTYSTR(lastUpdateCheck)
|
||||
|
||||
PROPERTY4(bool, promptProfile, "startup_prompt_profile", false)
|
||||
|
||||
PROPERTY(bool, enableBackup, false)
|
||||
PROPERTY(bool, backupOnFlash, true)
|
||||
@@ -605,11 +649,8 @@ class AppData: public CompStoreObj
|
||||
bool firstUse;
|
||||
QString upgradeFromVersion;
|
||||
|
||||
CREATE_ENUM_FRIEND_STREAM_OPS(AppData::DownloadBranchType)
|
||||
CREATE_ENUM_FRIEND_STREAM_OPS(AppData::NewModelAction)
|
||||
CREATE_ENUM_FRIEND_STREAM_OPS(AppData::UpdateCheckFreq)
|
||||
};
|
||||
|
||||
extern AppData g;
|
||||
|
||||
//! @}
|
||||
#endif // _APPDATA_H_
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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 "minizinterface.h"
|
||||
#include "progresswidget.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QWidget>
|
||||
|
||||
MinizInterface::MinizInterface(ProgressWidget * progress, const ProgressCalcMethod progressMethod, const int & logLevel) :
|
||||
progress(progress),
|
||||
progressMethod(progressMethod),
|
||||
progressValue(0),
|
||||
logLevel(logLevel),
|
||||
path(""),
|
||||
archiveFile("")
|
||||
{
|
||||
reportProgress(tr("Progress calculation method: file %1").arg(progressMethod == PCM_COUNT ? tr("count") : tr("size")), QtDebugMsg);
|
||||
}
|
||||
|
||||
MinizInterface::~MinizInterface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool MinizInterface::zipPathToFile(const QString & sourcePath, const QString & archiveFile, bool append)
|
||||
{
|
||||
if (progress)
|
||||
progress->setInfo(tr("Compressing %1 to %2 with append %3").arg(sourcePath, archiveFile, append ? "true" : "false"));
|
||||
else
|
||||
qDebug() << QString("Compressing %1 to %2 with append %3").arg(sourcePath, archiveFile, append ? "true" : "false");
|
||||
|
||||
reportProgress(tr("Miniz version: %1").arg(MZ_VERSION), QtDebugMsg);
|
||||
|
||||
progressValue = 0;
|
||||
path = sourcePath;
|
||||
this->archiveFile = archiveFile;
|
||||
mz_zip_zero_struct(&zip_archive);
|
||||
|
||||
QFileInfo afi(archiveFile);
|
||||
|
||||
if (afi.exists() && !append)
|
||||
reportProgress(tr("Existing archive will be overwritten"), QtCriticalMsg);
|
||||
|
||||
if (afi.exists() && append) {
|
||||
if (!mz_zip_reader_init_file(&zip_archive, qPrintable(archiveFile), 0)) {
|
||||
reportProgress(tr("Unable to open existing archive"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
reportProgress(tr("Existing archive opened"), QtDebugMsg);
|
||||
|
||||
if (!mz_zip_writer_init_from_reader(&zip_archive, qPrintable(archiveFile))) {
|
||||
reportProgress(tr("Unable to write to existing archive"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
reportProgress(tr("Existing archive initialised"), QtDebugMsg);
|
||||
}
|
||||
else {
|
||||
if (!mz_zip_writer_init_file(&zip_archive, qPrintable(archiveFile), 0)) {
|
||||
reportProgress(tr("Failure to initialise archive"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
reportProgress(tr("Archive initialised"), QtDebugMsg);
|
||||
}
|
||||
|
||||
QFileInfo pfi(path);
|
||||
|
||||
int fileCount = 0;
|
||||
|
||||
if (pfi.isDir()) {
|
||||
if (progressMethod == PCM_COUNT) {
|
||||
reportProgress(tr("Calculating number of items to archive"), QtDebugMsg);
|
||||
|
||||
QDirIterator itcnt(path, QDirIterator::Subdirectories);
|
||||
|
||||
while (itcnt.hasNext()) {
|
||||
fileCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
if (progressMethod == PCM_COUNT)
|
||||
progress->setMaximum(fileCount);
|
||||
else
|
||||
progress->setMaximum(pfi.size());
|
||||
}
|
||||
|
||||
fileCount = 0;
|
||||
QDirIterator it(path, QDirIterator::Subdirectories);
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (!addFileToArchive(it.filePath()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fileCount = 1;
|
||||
|
||||
if (progress) {
|
||||
if (progressMethod == PCM_COUNT)
|
||||
progress->setMaximum(fileCount);
|
||||
else
|
||||
progress->setMaximum(pfi.size());
|
||||
}
|
||||
|
||||
if (!addFileToArchive(path))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mz_zip_writer_finalize_archive(&zip_archive)) {
|
||||
mz_zip_writer_end(&zip_archive);
|
||||
reportProgress(tr("Failure to finalise archive"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
mz_zip_writer_end(&zip_archive);
|
||||
|
||||
if (progress)
|
||||
progress->setValue(progress->maximum());
|
||||
|
||||
reportProgress(tr("Compress complete"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MinizInterface::addFileToArchive(const QString & path)
|
||||
{
|
||||
if (!mz_zip_writer_add_file(&zip_archive, qPrintable(archiveFile), qPrintable(path), NULL, 0, MZ_DEFAULT_COMPRESSION)) {
|
||||
mz_zip_writer_end(&zip_archive);
|
||||
reportProgress(tr("Failure to add %1").arg(path), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progressMethod == PCM_COUNT)
|
||||
++progressValue;
|
||||
else
|
||||
progressValue += QFileInfo(path).size();
|
||||
|
||||
if (progress)
|
||||
progress->setValue(progressValue);
|
||||
|
||||
reportProgress(tr("Added file: %1").arg(path), QtDebugMsg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MinizInterface::unzipArchiveToPath(const QString & archiveFile, const QString & destinationPath)
|
||||
{
|
||||
if (progress)
|
||||
progress->setInfo(tr("Decompressing %1 to %2").arg(archiveFile, destinationPath));
|
||||
else
|
||||
qDebug() << QString("Decompressing %1 to %2").arg(archiveFile, destinationPath);
|
||||
|
||||
reportProgress(tr("Miniz version: %1").arg(MZ_VERSION), QtDebugMsg);
|
||||
|
||||
progressValue = 0;
|
||||
path = destinationPath;
|
||||
this->archiveFile = archiveFile;
|
||||
mz_zip_zero_struct(&zip_archive);
|
||||
|
||||
if (!mz_zip_reader_init_file(&zip_archive, qPrintable(archiveFile), 0)) {
|
||||
reportProgress(tr("File does not appear to be a compressed archive"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fileCount = (int)mz_zip_reader_get_num_files(&zip_archive);
|
||||
|
||||
if (fileCount == 0) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
reportProgress(tr("Compressed archive does not contain any files"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
if (progressMethod == PCM_COUNT)
|
||||
progress->setMaximum(fileCount);
|
||||
else
|
||||
progress->setMaximum(QFileInfo(archiveFile).size());
|
||||
}
|
||||
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
|
||||
if (!mz_zip_reader_file_stat(&zip_archive, 0, &file_stat)) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
reportProgress(tr("File status error"), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
reportProgress(tr("Unable to obtain file status for index: %1").arg(i), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString destPath = path % "/" % QString(file_stat.m_filename);
|
||||
|
||||
if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) {
|
||||
if (!createDirectory(destPath)) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
QFileInfo dfi(destPath);
|
||||
if (!createDirectory(dfi.absolutePath())) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mz_zip_reader_extract_to_file(&zip_archive, i, qPrintable(destPath), 0)) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
reportProgress(tr("Failed to extract %1 to %2").arg(dfi.fileName(), dfi.absolutePath()), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (dfi.size() != (qint64)file_stat.m_uncomp_size) {
|
||||
reportProgress(tr("File %1 extracted size %2 does not match original %3").arg(file_stat.m_filename).arg(dfi.size()).arg((qint64)file_stat.m_uncomp_size), QtFatalMsg);
|
||||
// return false; disable until testing complete as there maybe some adjustment factor or even OS strangeness
|
||||
}
|
||||
}
|
||||
|
||||
if (progressMethod == PCM_COUNT)
|
||||
++progressValue;
|
||||
else
|
||||
progressValue += file_stat.m_comp_size;
|
||||
|
||||
if (progress)
|
||||
progress->setValue(progressValue);
|
||||
|
||||
reportProgress(tr("Extracted file: %1").arg(file_stat.m_filename), QtDebugMsg);
|
||||
}
|
||||
}
|
||||
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
|
||||
if (progress)
|
||||
progress->setValue(progress->maximum());
|
||||
|
||||
reportProgress(tr("Decompress complete"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MinizInterface::createDirectory(const QString & path)
|
||||
{
|
||||
if (!QDir(path).exists()) {
|
||||
if (!QDir().mkpath(path)) {
|
||||
reportProgress(tr("Failed to create directory: %1").arg(path), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
reportProgress(tr("Created directory: %1").arg(path));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MinizInterface::reportProgress(const QString & text, const int & type, bool richText)
|
||||
{
|
||||
if (type >= logLevel) {
|
||||
if (progress)
|
||||
progress->addMessage(text, type);
|
||||
else
|
||||
qDebug() << text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 "miniz.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QString>
|
||||
|
||||
class ProgressWidget;
|
||||
|
||||
class MinizInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(MinizInterface)
|
||||
|
||||
public:
|
||||
enum ProgressCalcMethod {
|
||||
PCM_COUNT,
|
||||
PCM_SIZE
|
||||
};
|
||||
|
||||
MinizInterface(ProgressWidget * progress = nullptr, const ProgressCalcMethod progressMethod = PCM_COUNT, const int & logLevel = QtWarningMsg);
|
||||
~MinizInterface();
|
||||
|
||||
bool zipPathToFile(const QString & sourcePath, const QString & archiveFile, bool append = true);
|
||||
bool unzipArchiveToPath(const QString & archiveFile, const QString & destinationPath);
|
||||
|
||||
private:
|
||||
ProgressWidget *progress;
|
||||
ProgressCalcMethod progressMethod;
|
||||
qint64 progressValue;
|
||||
int logLevel;
|
||||
QString path;
|
||||
QString archiveFile;
|
||||
|
||||
mz_zip_archive zip_archive;
|
||||
|
||||
bool addFileToArchive(const QString & path);
|
||||
bool createDirectory(const QString & path);
|
||||
void reportProgress(const QString & text, const int & type = QtInfoMsg, bool richText = false);
|
||||
};
|
||||
|
Before Width: | Height: | Size: 1020 B After Width: | Height: | Size: 1020 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 500 B After Width: | Height: | Size: 500 B |
|
Before Width: | Height: | Size: 653 B After Width: | Height: | Size: 653 B |
|
Before Width: | Height: | Size: 705 B After Width: | Height: | Size: 705 B |
|
Before Width: | Height: | Size: 245 B After Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 286 B |
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 460 B |
|
Before Width: | Height: | Size: 245 B After Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 499 B |
|
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 675 B |
|
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 724 B |
|
Before Width: | Height: | Size: 873 B After Width: | Height: | Size: 873 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,39 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(updates_NAMES
|
||||
updates
|
||||
updatesdialog
|
||||
updateoptionsdialog
|
||||
repomodels
|
||||
updateinterface
|
||||
updatefirmware
|
||||
updatecompanion
|
||||
updatesdcard
|
||||
updatesounds
|
||||
updatethemes
|
||||
updatemultiprotocol
|
||||
)
|
||||
|
||||
foreach(name ${updates_NAMES})
|
||||
set(updates_SRCS ${updates_SRCS} ${name}.cpp)
|
||||
set(updates_HDRS ${updates_HDRS} ${name}.h)
|
||||
endforeach()
|
||||
|
||||
set(updates_UIS
|
||||
updatesdialog.ui
|
||||
updateoptionsdialog.ui
|
||||
)
|
||||
|
||||
set(updates_QTS
|
||||
updates.h
|
||||
updatesdialog.h
|
||||
updateoptionsdialog.h
|
||||
repomodels.h
|
||||
updateinterface.h
|
||||
)
|
||||
|
||||
qt5_wrap_ui(updates_SRCS ${updates_UIS})
|
||||
qt5_wrap_cpp(updates_SRCS ${updates_QTS})
|
||||
|
||||
add_library(updates ${updates_SRCS} ${updates_HDRS})
|
||||
target_link_libraries(updates PRIVATE ${CPN_COMMON_LIB})
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
* 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
|
||||
@@ -25,7 +26,7 @@
|
||||
|
||||
#include <QTime>
|
||||
|
||||
DownloadDialog::DownloadDialog(QWidget *parent, QString src, QString tgt):
|
||||
DownloadDialog::DownloadDialog(QWidget *parent, QString src, QString tgt, QString contentType, QString title):
|
||||
QDialog(parent),
|
||||
ui(new Ui::DownloadDialog),
|
||||
reply(nullptr),
|
||||
@@ -33,25 +34,33 @@ DownloadDialog::DownloadDialog(QWidget *parent, QString src, QString tgt):
|
||||
aborted(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("fwpreferences.png"));
|
||||
ui->progressBar->setValue(1);
|
||||
setWindowIcon(CompanionIcon("download.png"));
|
||||
ui->progressBar->setValue(0);
|
||||
ui->progressBar->setMinimum(0);
|
||||
ui->progressBar->setMaximum(0);
|
||||
ui->progressBar->setMaximum(100);
|
||||
|
||||
if (tgt.isEmpty()) {
|
||||
setWindowTitle(src);
|
||||
return; // just show wait dialog.
|
||||
}
|
||||
|
||||
setWindowTitle(windowTitle() % title);
|
||||
|
||||
file = new QFile(tgt);
|
||||
if (!file->open(QIODevice::WriteOnly)) {
|
||||
QMessageBox::critical(this, CPN_STR_APP_NAME,
|
||||
tr("Unable to save the file %1: %2.")
|
||||
.arg(tgt).arg(file->errorString()));
|
||||
QMessageBox::critical(this, CPN_STR_APP_NAME, tr("Unable to open the download file %1 for writing.\nError: %2").arg(tgt).arg(file->errorString()));
|
||||
QTimer::singleShot(0, this, SLOT(fileError()));
|
||||
}
|
||||
else {
|
||||
reply = qnam.get(QNetworkRequest(QUrl(src)));
|
||||
url.setUrl(src);
|
||||
qDebug() << "url:" << url.url();
|
||||
request.setUrl(url);
|
||||
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
|
||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
|
||||
request.setRawHeader(QByteArray("Accept"), contentType.toUtf8());
|
||||
|
||||
reply = qnam.get(request);
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(httpFinished()));
|
||||
connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));
|
||||
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateDataReadProgress(qint64, qint64)));
|
||||
@@ -81,6 +90,7 @@ void DownloadDialog::httpFinished()
|
||||
file->close();
|
||||
|
||||
const bool ok = !(reply->error() || aborted);
|
||||
|
||||
if (!ok) {
|
||||
file->remove();
|
||||
if (!aborted)
|
||||
@@ -117,15 +127,3 @@ void DownloadDialog::fileError()
|
||||
file = nullptr;
|
||||
reject();
|
||||
}
|
||||
|
||||
#if 0
|
||||
void DownloadDialog::closeEvent( QCloseEvent * event)
|
||||
{
|
||||
// Delay closing 2 seconds to avoid unpleasant flashing download dialogs
|
||||
QTime closeTime= QTime::currentTime().addSecs(2);
|
||||
while( QTime::currentTime() < closeTime )
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
|
||||
|
||||
event->accept();
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
* 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
|
||||
@@ -18,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DOWNLOADDIALOG_H_
|
||||
#define _DOWNLOADDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
@@ -36,34 +36,26 @@ class DownloadDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DownloadDialog(QWidget *parent = 0, QString src = "", QString tgt = "");
|
||||
explicit DownloadDialog(QWidget *parent = 0, QString src = "", QString tgt = "", QString contentType = "", QString title = "");
|
||||
|
||||
~DownloadDialog();
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void reject() override;
|
||||
|
||||
private slots:
|
||||
|
||||
void fileError();
|
||||
|
||||
void httpFinished();
|
||||
|
||||
void httpReadyRead();
|
||||
|
||||
void updateDataReadProgress(qint64 bytesRead, qint64 totalBytes);
|
||||
|
||||
private:
|
||||
#if 0
|
||||
void closeEvent(QCloseEvent * event);
|
||||
#endif
|
||||
Ui::DownloadDialog *ui;
|
||||
|
||||
QNetworkAccessManager qnam;
|
||||
QNetworkReply *reply;
|
||||
QFile *file;
|
||||
bool aborted;
|
||||
QNetworkRequest request;
|
||||
QUrl url;
|
||||
};
|
||||
|
||||
#endif // _DOWNLOADDIALOG_H_
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* 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 <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)
|
||||
{
|
||||
setSortRole(UpdatesItemModel::IMDR_Date);
|
||||
}
|
||||
|
||||
bool ReleasesItemModel::releaseChannelChanged()
|
||||
{
|
||||
if (m_settingsIdx > -1 && m_releaseChannel != (int)g.component[m_settingsIdx].releaseChannel())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReleasesItemModel::parseMetaData(const int mdt, QJsonDocument * jsonDoc)
|
||||
{
|
||||
json = jsonDoc;
|
||||
|
||||
if (m_settingsIdx > -1)
|
||||
m_releaseChannel = g.component[m_settingsIdx].releaseChannel();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
item->setData(isReleaseAvailable(tag, prerelease), UpdatesItemModel::IMDR_Available);
|
||||
|
||||
appendRow(item);
|
||||
}
|
||||
|
||||
bool ReleasesItemModel::isReleaseAvailable(const QString tagname, const bool prerelease)
|
||||
{
|
||||
if (prerelease) {
|
||||
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 && tagname.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));
|
||||
}
|
||||
|
||||
/*
|
||||
ReleasesMetaData
|
||||
*/
|
||||
|
||||
ReleasesMetaData::ReleasesMetaData(QWidget * parent) :
|
||||
QWidget(parent),
|
||||
m_repo(""),
|
||||
m_id(0)
|
||||
{
|
||||
itemModel = new ReleasesItemModel();
|
||||
filteredItemModel = new ReleasesFilteredItemModel(itemModel);
|
||||
}
|
||||
|
||||
bool ReleasesMetaData::refreshRequired()
|
||||
{
|
||||
if (m_id != 0)
|
||||
return itemModel->releaseChannelChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
AssetsMetaData
|
||||
*/
|
||||
|
||||
AssetsMetaData::AssetsMetaData(QWidget * parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
itemModel = new AssetsItemModel();
|
||||
filteredItemModel = new AssetsFilteredItemModel(itemModel);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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 <QWidget>
|
||||
#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_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 parseMetaData(const int mdt, QJsonDocument * json);
|
||||
int settingsIndex() { return m_settingsIdx; }
|
||||
bool releaseChannelChanged();
|
||||
|
||||
private:
|
||||
int m_settingsIdx;
|
||||
QString m_nightlyName;
|
||||
int m_releaseChannel;
|
||||
|
||||
bool isReleaseAvailable(const QString tagname, const bool prerelease);
|
||||
|
||||
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 ReleasesMetaData : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ReleasesMetaData(QWidget * parent);
|
||||
virtual ~ReleasesMetaData() {};
|
||||
|
||||
bool refreshRequired();
|
||||
|
||||
void setRepo(QString repo) { m_repo = repo; }
|
||||
void setNightlyName(QString name) { itemModel->setNightlyName(name); }
|
||||
void setSettingsIndex(int index) { itemModel->setSettingsIndex(index); }
|
||||
|
||||
void setId(int id) { m_id = id; }
|
||||
int id() { return m_id; }
|
||||
|
||||
int getSetId() { m_id = filteredItemModel->channelLatestId(); return m_id; }
|
||||
|
||||
int getSetId(int row) { m_id = filteredItemModel->id(row); return m_id; }
|
||||
|
||||
int getSetId(QVariant value, Qt::MatchFlags flags = Qt::MatchExactly, int role = Qt::DisplayRole)
|
||||
{ m_id = filteredItemModel->id(value, flags, role); return m_id; }
|
||||
|
||||
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() { return filteredItemModel->name(m_id); }
|
||||
bool prerelease() { return filteredItemModel->prerelease(m_id); }
|
||||
QString version() { return filteredItemModel->version(m_id); }
|
||||
|
||||
QString urlReleases() { return m_repo % "/releases"; }
|
||||
QString urlReleaseLatest() { return urlReleases() % "/latest"; }
|
||||
QString urlRelease() { return urlReleases() % QString("/%1").arg(m_id); }
|
||||
|
||||
private:
|
||||
ReleasesItemModel *itemModel;
|
||||
ReleasesFilteredItemModel *filteredItemModel;
|
||||
QString m_repo;
|
||||
int m_id;
|
||||
};
|
||||
|
||||
class AssetsMetaData : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AssetsMetaData(QWidget * parent);
|
||||
virtual ~AssetsMetaData() {};
|
||||
|
||||
void setRepo(QString repo) { m_repo = repo; }
|
||||
|
||||
void setId(int id) { m_id = id; }
|
||||
int id() { return m_id; }
|
||||
|
||||
int getSetId(int row) { m_id = filteredItemModel->id(row); return m_id; }
|
||||
|
||||
int getSetId(QVariant value, Qt::MatchFlags flags = Qt::MatchExactly, int role = Qt::DisplayRole)
|
||||
{ m_id = filteredItemModel->id(value, flags, role); return m_id; }
|
||||
|
||||
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(); }
|
||||
|
||||
QString urlReleaseAssets(int releaseId, int max)
|
||||
{ return urlReleases() % QString("/%1/assets").arg(releaseId) % (max > -1 ? QString("\?per_page=%1").arg(max) : ""); }
|
||||
QString urlAsset() { return urlReleases() % QString("/assets/%1").arg(m_id); }
|
||||
|
||||
QString urlContent(QString path) { return m_repo % QString("/contents/%1").arg(path); }
|
||||
|
||||
private:
|
||||
AssetsItemModel *itemModel;
|
||||
AssetsFilteredItemModel *filteredItemModel;
|
||||
QString m_repo;
|
||||
int m_id;
|
||||
|
||||
QString urlReleases() { return m_repo % "/releases"; }
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 "updatecompanion.h"
|
||||
#include "constants.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QDirIterator>
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
#define
|
||||
#define OS_FILEPATTERN "edgetx-cpn-osx"
|
||||
#define OS_INSTALLER_EXTN "*.dmg"
|
||||
#define OS_INSTALL_QUESTION tr("Would you like to open the disk image to install the new version?")
|
||||
#elif defined(Q_OS_WIN64)
|
||||
#define OS_FILEPATTERN "edgetx-cpn-win64"
|
||||
#define OS_INSTALLER_EXTN "*.exe"
|
||||
#define OS_INSTALL_QUESTION tr("Would you like to launch the installer?")
|
||||
#elif defined(Q_OS_WIN32)
|
||||
#define OS_FILEPATTERN "edgetx-cpn-win32"
|
||||
#define OS_INSTALLER_EXTN "*.exe"
|
||||
#define OS_INSTALL_QUESTION tr("Would you like to launch the installer?")
|
||||
#else
|
||||
#define OS_FILEPATTERN "edgetx-cpn-linux"
|
||||
#define OS_INSTALLER_EXTN "*.AppImage"
|
||||
#define OS_INSTALL_QUESTION tr("Would you like to open the app image to install the new version?")
|
||||
#endif
|
||||
|
||||
UpdateCompanion::UpdateCompanion(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
{
|
||||
setName("Companion");
|
||||
setRepo(QString(GH_REPOS_EDGETX).append("/edgetx"));
|
||||
setReleasesNightlyName("nightly");
|
||||
|
||||
dfltParams->data.flags = (UPDFLG_Common | UPDFLG_Locked | UPDFLG_AsyncInstall) & ~UPDFLG_CopyDest;
|
||||
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
ap.filterType = UpdateParameters::UFT_Startswith;
|
||||
ap.filter = QString("%1").arg(QString(OS_FILEPATTERN));
|
||||
ap.maxExpected = 1;
|
||||
ap.flags = dfltParams->data.flags;
|
||||
}
|
||||
|
||||
bool UpdateCompanion::asyncInstall()
|
||||
{
|
||||
progressMessage(tr("Async install"));
|
||||
|
||||
assets->setFilterFlags(UPDFLG_AsyncInstall);
|
||||
reportProgress(tr("Asset filter applied: %1 Assets found: %2").arg(updateFlagsToString(UPDFLG_AsyncInstall)).arg(assets->count()), QtDebugMsg);
|
||||
|
||||
if (assets->count() != 1) {
|
||||
reportProgress(tr("Expected 1 asset for install but none found"), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
assets->getSetId(0);
|
||||
|
||||
QString installerPath = decompressDir % QString("/A%1/%2").arg(assets->id()).arg(QFileInfo(assets->filename()).completeBaseName());
|
||||
|
||||
QDirIterator it(installerPath, { OS_INSTALLER_EXTN }, QDir::Files, QDirIterator::Subdirectories);
|
||||
|
||||
bool found = false;
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
installerPath = it.next();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
reportProgress(tr("Installer not found in %1 using filter %2").arg(installerPath).arg(OS_INSTALLER_EXTN), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = QMessageBox::question(parentWidget(), CPN_STR_APP_NAME, OS_INSTALL_QUESTION, QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (ret == QMessageBox::Yes) {
|
||||
if (QDesktopServices::openUrl(QUrl::fromLocalFile(installerPath)))
|
||||
qApp->exit();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString UpdateCompanion::currentRelease()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
return UpdateInterface::latestRelease();
|
||||
#else
|
||||
dfltParams->data.currentRelease = QString("EdgeTX v%1.%2 (Custom)").arg(VERSION_MAJOR).arg(VERSION_MINOR);
|
||||
runParams->data.currentRelease = dfltParams->data.currentRelease;
|
||||
return dfltParams->data.currentRelease;
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString UpdateCompanion::currentVersion()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
return UpdateInterface::latestRelease();
|
||||
#else
|
||||
return QString(QString("v%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR));
|
||||
#endif
|
||||
}
|
||||
|
||||
const bool UpdateCompanion::isLatestRelease()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
return UpdateInterface::isLatestRelease();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
const bool UpdateCompanion::isUpdateAvailable()
|
||||
{
|
||||
#if defined(VERSION_TAG)
|
||||
return UpdateInterface::isUpdateAvailable();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
* 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
|
||||
@@ -18,29 +19,23 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "releasenotesdialog.h"
|
||||
#include "ui_htmldialog.h"
|
||||
#include <QFile>
|
||||
#pragma once
|
||||
|
||||
ReleaseNotesDialog::ReleaseNotesDialog(QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::HtmlDialog)
|
||||
#include "updateinterface.h"
|
||||
|
||||
class UpdateCompanion : public UpdateInterface
|
||||
{
|
||||
ui->setupUi(this);
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateCompanion)
|
||||
|
||||
setWindowTitle(tr("Companion Release Notes"));
|
||||
setWindowIcon(CompanionIcon("changelog.png"));
|
||||
public:
|
||||
|
||||
QFile file(":/releasenotes.txt");
|
||||
if (file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
|
||||
ui->textEditor->setHtml(file.readAll());
|
||||
ui->textEditor->setOpenExternalLinks(true);
|
||||
}
|
||||
ui->textEditor->scroll(0, 0);
|
||||
ui->textEditor->setOpenExternalLinks(true);
|
||||
}
|
||||
explicit UpdateCompanion(QWidget * parent);
|
||||
virtual ~UpdateCompanion() {}
|
||||
|
||||
ReleaseNotesDialog::~ReleaseNotesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
protected:
|
||||
virtual bool asyncInstall() override;
|
||||
virtual const QString currentRelease();
|
||||
virtual const QString currentVersion();
|
||||
virtual const bool isLatestRelease();
|
||||
virtual const bool isUpdateAvailable();
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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 "updatefirmware.h"
|
||||
#include "appdata.h"
|
||||
#include "flashfirmwaredialog.h"
|
||||
|
||||
UpdateFirmware::UpdateFirmware(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
{
|
||||
setName("Firmware");
|
||||
setRepo(QString(GH_REPOS_EDGETX).append("/edgetx"));
|
||||
setReleasesNightlyName("nightly");
|
||||
|
||||
dfltParams->data.flags = UPDFLG_Common | UPDFLG_Locked | UPDFLG_AsyncInstall;
|
||||
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
ap.filterType = UpdateParameters::UFT_Startswith;
|
||||
ap.filter = "edgetx-firmware";
|
||||
ap.maxExpected = 1;
|
||||
ap.flags = dfltParams->data.flags | UPDFLG_CopyFiles;
|
||||
ap.destSubDir = "FIRMWARE";
|
||||
ap.copyFilterType = UpdateParameters::UFT_Expression;
|
||||
ap.copyFilter = QString("^%1-.*\\.bin$").arg(fwFlavour);
|
||||
}
|
||||
|
||||
bool UpdateFirmware::asyncInstall()
|
||||
{
|
||||
progressMessage(tr("Async install"));
|
||||
|
||||
assets->setFilterFlags(UPDFLG_AsyncInstall);
|
||||
reportProgress(tr("Asset filter applied: %1 Assets found: %2").arg(updateFlagsToString(UPDFLG_AsyncInstall)).arg(assets->count()), QtDebugMsg);
|
||||
|
||||
if (assets->count() != 1) {
|
||||
reportProgress(tr("Expected 1 asset for install but none found"), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString destPath = updateDir;
|
||||
|
||||
if (!assets->subDirectory().isEmpty())
|
||||
destPath.append("/" % assets->subDirectory());
|
||||
|
||||
QRegularExpression filter(runParams->data.assets.at(0).copyFilter, QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
QDirIterator it(destPath);
|
||||
|
||||
bool found = false;
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
QFileInfo file(it.next());
|
||||
|
||||
if ((!filter.pattern().isEmpty()) && (!file.fileName().contains(filter)))
|
||||
continue;
|
||||
|
||||
destPath.append("/" % file.fileName());
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
reportProgress(tr("Firmware not found in %1 using filter %2").arg(destPath).arg(filter.pattern()), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
g.currentProfile().fwName(destPath);
|
||||
|
||||
reportProgress(tr("Write firmware to radio option setting: %1").arg(g.currentProfile().burnFirmware() ? tr("true") : tr("false")), QtDebugMsg);
|
||||
|
||||
if (g.currentProfile().burnFirmware()) {
|
||||
int ret = QMessageBox::question(this, CPN_STR_APP_NAME, tr("Do you want to write the firmware to the radio now ?"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::Yes) {
|
||||
FlashFirmwareDialog *dlg = new FlashFirmwareDialog(this);
|
||||
dlg->exec();
|
||||
dlg->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
class UpdateFirmware : public UpdateInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateFirmware)
|
||||
|
||||
public:
|
||||
|
||||
explicit UpdateFirmware(QWidget * parent);
|
||||
virtual ~UpdateFirmware() {}
|
||||
|
||||
protected:
|
||||
virtual bool asyncInstall() override;
|
||||
};
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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 "repomodels.h"
|
||||
#include "constants.h"
|
||||
#include "progresswidget.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QWidget>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
class UpdateParameters : public QWidget
|
||||
{
|
||||
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 flags;
|
||||
UpdateFilterType filterType;
|
||||
QString filter;
|
||||
int maxExpected;
|
||||
QString destSubDir;
|
||||
UpdateFilterType copyFilterType;
|
||||
QString copyFilter;
|
||||
};
|
||||
|
||||
struct GeneralParams{
|
||||
int flags;
|
||||
QString currentRelease;
|
||||
QString updateRelease;
|
||||
QString downloadDir;
|
||||
bool decompressUseDwnld;
|
||||
QString decompressDir;
|
||||
bool updateUseSD;
|
||||
QString updateDir;
|
||||
QVector<AssetParams> assets;
|
||||
};
|
||||
|
||||
GeneralParams data;
|
||||
|
||||
UpdateParameters(QWidget * parent);
|
||||
virtual ~UpdateParameters() {}
|
||||
|
||||
AssetParams & addAsset();
|
||||
static QString buildFilterPattern(const UpdateFilterType filterType, const QString & filter);
|
||||
|
||||
UpdateParameters& operator=(const UpdateParameters& source);
|
||||
};
|
||||
|
||||
class UpdateInterface : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum DownloadDataType {
|
||||
DDT_Binary,
|
||||
DDT_Content,
|
||||
DDT_SaveToFile,
|
||||
DDT_MetaData,
|
||||
};
|
||||
Q_ENUM(DownloadDataType)
|
||||
|
||||
enum UpdateFlags {
|
||||
UPDFLG_None = 0,
|
||||
UPDFLG_Update = 1 << 1,
|
||||
UPDFLG_Locked = 1 << 2,
|
||||
UPDFLG_Preparation = 1 << 3,
|
||||
UPDFLG_Download = 1 << 4,
|
||||
UPDFLG_DelDownload = 1 << 5,
|
||||
UPDFLG_Decompress = 1 << 6,
|
||||
UPDFLG_DelDecompress = 1 << 7,
|
||||
UPDFLG_CopyDest = 1 << 8,
|
||||
UPDFLG_CopyFiles = 1 << 9,
|
||||
UPDFLG_CopyStructure = 1 << 10,
|
||||
UPDFLG_Housekeeping = 1 << 11,
|
||||
UPDFLG_AsyncInstall = 1 << 12,
|
||||
UPDFLG_Common = UPDFLG_Preparation | UPDFLG_Download | UPDFLG_Decompress | UPDFLG_CopyDest | UPDFLG_Housekeeping,
|
||||
};
|
||||
Q_ENUM(UpdateFlags)
|
||||
|
||||
explicit UpdateInterface(QWidget * parent);
|
||||
virtual ~UpdateInterface();
|
||||
|
||||
const QString getName() const { return name; }
|
||||
|
||||
protected:
|
||||
friend class UpdateFactories;
|
||||
|
||||
ReleasesMetaData *releases;
|
||||
AssetsMetaData *assets;
|
||||
UpdateParameters *dfltParams;
|
||||
UpdateParameters *runParams;
|
||||
ProgressWidget *progress;
|
||||
|
||||
QString name;
|
||||
int settingsIdx;
|
||||
int resultsPerPage;
|
||||
QString downloadDir;
|
||||
QString decompressDir;
|
||||
QString updateDir;
|
||||
QString fwFlavour;
|
||||
QString language;
|
||||
int logLevel;
|
||||
|
||||
virtual bool update();
|
||||
virtual bool preparation();
|
||||
virtual bool flagAssets();
|
||||
virtual bool download();
|
||||
virtual bool decompress();
|
||||
virtual bool copyToDestination();
|
||||
virtual bool copyAsset();
|
||||
virtual bool housekeeping();
|
||||
virtual bool asyncInstall();
|
||||
|
||||
void setName(QString name);
|
||||
void setRepo(QString repo) { releases->setRepo(repo); assets->setRepo(repo); }
|
||||
void setResultsPerPage(int cnt) { resultsPerPage = cnt; }
|
||||
void setReleasesNightlyName(QString name) { releases->setNightlyName(name); }
|
||||
|
||||
void initParamFolders(UpdateParameters * params);
|
||||
const UpdateParameters * const getDefaultParams() { return dfltParams; }
|
||||
UpdateParameters * getRunParams() { return runParams; }
|
||||
void resetRunParams();
|
||||
void setRunUpdate() { runParams->data.flags |= UPDFLG_Update; }
|
||||
|
||||
const QStringList getReleases();
|
||||
|
||||
virtual const bool isUpdateAvailable();
|
||||
|
||||
virtual bool autoUpdate(ProgressWidget * progress = nullptr);
|
||||
virtual bool manualUpdate(ProgressWidget * progress = nullptr);
|
||||
|
||||
virtual const QString currentVersion();
|
||||
|
||||
void clearRelease();
|
||||
|
||||
virtual const QString currentRelease();
|
||||
virtual const QString updateRelease();
|
||||
virtual const bool isLatestRelease();
|
||||
virtual const bool isLatestVersion(const QString & current, const QString & latest);
|
||||
virtual const QString latestRelease();
|
||||
|
||||
void getRadioProfileSettings();
|
||||
|
||||
bool repoReleasesMetaData();
|
||||
bool repoReleaseAssetsMetaData();
|
||||
|
||||
bool downloadReleasesMetaData();
|
||||
bool downloadReleaseLatestMetaData();
|
||||
bool downloadReleaseMetaData(const int releaseId);
|
||||
|
||||
bool downloadReleaseAssetsMetaData(const int releaseId);
|
||||
bool downloadAssetMetaData(const int assetId);
|
||||
bool getSetAssets(const int flags, const UpdateParameters::UpdateFilterType assetFilterType, const QString & assetsFilter,
|
||||
const int maxAssetsExpected, const QString & subDirectory,
|
||||
const UpdateParameters::UpdateFilterType copyFilterType, const QString & copyFilter);
|
||||
bool downloadAsset(int row);
|
||||
bool downloadFlaggedAssets();
|
||||
bool decompressAsset(int row);
|
||||
bool decompressFlaggedAssets();
|
||||
bool copyFlaggedAssets();
|
||||
bool copyStructure();
|
||||
bool copyFiles();
|
||||
|
||||
bool downloadTextFileToBuffer(const QString & path);
|
||||
void downloadFileToBuffer(const QString & url);
|
||||
QByteArray * getDownloadBuffer() { return buffer; }
|
||||
|
||||
bool convertDownloadToJson(QJsonDocument * json);
|
||||
|
||||
bool decompressArchive(const QString & archivePath, const QString & destPath);
|
||||
bool saveReleaseSettings();
|
||||
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);
|
||||
|
||||
private slots:
|
||||
void onDownloadFinished(QNetworkReply * reply, DownloadDataType ddt, int subtype);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request;
|
||||
QNetworkReply *reply;
|
||||
QByteArray *buffer;
|
||||
QFile *file;
|
||||
QUrl url;
|
||||
|
||||
bool downloadSuccess;
|
||||
|
||||
static QString semanticVersion(QString version);
|
||||
|
||||
int getSettingsIdx();
|
||||
void setSettingsIdx();
|
||||
bool setRunFolders();
|
||||
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 QString name() = 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 QString name() { return m_instance->getName(); }
|
||||
|
||||
private:
|
||||
UpdateInterface *m_instance;
|
||||
};
|
||||
|
||||
class UpdateFactories : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateFactories(QWidget * parent = nullptr);
|
||||
virtual ~UpdateFactories();
|
||||
|
||||
void registerUpdateFactory(UpdateFactoryInterface * factory);
|
||||
void registerUpdateFactories();
|
||||
void unregisterUpdateFactories();
|
||||
|
||||
const UpdateParameters * const getDefaultParams(const QString & name);
|
||||
UpdateParameters * const getRunParams(const QString & name);
|
||||
void resetRunParams(const QString & name);
|
||||
void resetAllRunParams();
|
||||
void setRunUpdate(const QString & name);
|
||||
const QMap<QString, int> sortedComponentsList();
|
||||
|
||||
void clearRelease(const QString & name);
|
||||
const QString currentRelease(const QString & name);
|
||||
const QString updateRelease(const QString & name);
|
||||
const bool isLatestRelease(const QString & name);
|
||||
const QString latestRelease(const QString & name);
|
||||
const QStringList releases(const QString & name);
|
||||
|
||||
bool autoUpdate(ProgressWidget * progress = nullptr);
|
||||
bool manualUpdate(ProgressWidget * progress = nullptr);
|
||||
const bool updatesAvailable();
|
||||
|
||||
private:
|
||||
QVector<UpdateFactoryInterface *> registeredUpdateFactories;
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 "updatemultiprotocol.h"
|
||||
|
||||
UpdateMultiProtocol::UpdateMultiProtocol(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
{
|
||||
setName("Multiprotocol");
|
||||
setRepo(QString(GITHUB_API_REPOS).append("/pascallanger/DIY-Multiprotocol-TX-Module"));
|
||||
setResultsPerPage(50); // GitHub REST API default 30
|
||||
|
||||
{
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
ap.filterType = UpdateParameters::UFT_Startswith;
|
||||
ap.filter = "MultiLuaScripts";
|
||||
ap.maxExpected = 1;
|
||||
ap.flags = dfltParams->data.flags | UPDFLG_Locked | UPDFLG_CopyStructure;
|
||||
}
|
||||
|
||||
{
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
ap.filterType = UpdateParameters::UFT_Expression;
|
||||
ap.filter = "^mm-stm-serial-.*\\.bin$";
|
||||
ap.flags = (dfltParams->data.flags | UPDFLG_CopyFiles) &~ (UPDFLG_Decompress | UPDFLG_DelDecompress);
|
||||
ap.destSubDir = "FIRMWARE";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "updateinterface.h"
|
||||
|
||||
class UpdateMultiProtocol : public UpdateInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateMultiProtocol)
|
||||
|
||||
public:
|
||||
|
||||
explicit UpdateMultiProtocol(QWidget * parent);
|
||||
virtual ~UpdateMultiProtocol() {}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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 "updateoptionsdialog.h"
|
||||
#include "ui_updateoptionsdialog.h"
|
||||
#include "appdata.h"
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QStandardItemModel>
|
||||
#include <QMessageBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTimer>
|
||||
|
||||
UpdateOptionsDialog::UpdateOptionsDialog(QWidget * parent, UpdateFactories * factories, const int idx) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::UpdateOptionsDialog),
|
||||
factories(factories),
|
||||
idx(idx),
|
||||
name(g.component[idx].name()),
|
||||
dfltParams(factories->getDefaultParams(name)),
|
||||
runParams(factories->getRunParams(name))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowTitle(tr("%1 %2").arg(name).arg(tr("Options")));
|
||||
|
||||
ui->leCurrent->setText(dfltParams->data.currentRelease);
|
||||
|
||||
connect(ui->btnForget, &QPushButton::clicked, [=]() {
|
||||
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear current release information.\nWarning: There is no undo! Are you sure?"),
|
||||
QMessageBox::Yes |QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
factories->clearRelease(name);
|
||||
ui->leCurrent->setText(dfltParams->data.currentRelease);
|
||||
emit changed(idx);
|
||||
}
|
||||
});
|
||||
|
||||
ui->cboReleases->addItems(factories->releases(name));
|
||||
|
||||
int i = -1;
|
||||
|
||||
QVBoxLayout *grpAssetsLayout = new QVBoxLayout();
|
||||
|
||||
foreach (const UpdateParameters::AssetParams &ap, dfltParams->data.assets) {
|
||||
int flags = ap.flags;
|
||||
const bool locked = flags & UpdateInterface::UPDFLG_Locked;
|
||||
i++;
|
||||
|
||||
QHBoxLayout *layout1 = new QHBoxLayout();
|
||||
|
||||
if (i > 0) {
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
line->setLineWidth(1);
|
||||
line->setMidLineWidth(0);
|
||||
grpAssetsLayout->addWidget(line);
|
||||
}
|
||||
|
||||
QLabel *aflbl = new QLabel(tr("Filter"));
|
||||
layout1->addWidget(aflbl);
|
||||
|
||||
QComboBox *cboAssetFilterType = new QComboBox();
|
||||
cboAssetFilterType->setEnabled(!locked);
|
||||
cboAssetFilterType->addItems(UpdateParameters::updateFilterTypeList());
|
||||
cboAssetFilterTypes << cboAssetFilterType;
|
||||
layout1->addWidget(cboAssetFilterType);
|
||||
|
||||
QLineEdit *leAssetFilter = new QLineEdit();
|
||||
leAssetFilter->setEnabled(!locked);
|
||||
leAssetFilters << leAssetFilter;
|
||||
layout1->addWidget(leAssetFilter);
|
||||
|
||||
connect(leAssetFilter, &QLineEdit::editingFinished, [=]() {
|
||||
QRegularExpression re(leAssetFilter->text());
|
||||
leAssetFilter->setStyleSheet((re.isValid() ? "QLineEdit { color : black; }" : "QLineEdit { color : red; }"));
|
||||
});
|
||||
|
||||
connect(cboAssetFilterType, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](const int index) {
|
||||
if (index == UpdateParameters::UFT_None) {
|
||||
leAssetFilter->setEnabled(false);
|
||||
leAssetFilter->setText("");
|
||||
}
|
||||
else
|
||||
leAssetFilter->setEnabled(!locked);
|
||||
});
|
||||
|
||||
QSpacerItem *hsp1 = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||
layout1->addItem(hsp1);
|
||||
|
||||
grpAssetsLayout->addLayout(layout1);
|
||||
|
||||
QHBoxLayout *layout2 = new QHBoxLayout();
|
||||
|
||||
QCheckBox *chkDownload = new QCheckBox(tr("Download"));
|
||||
chkDownloads << chkDownload;
|
||||
layout2->addWidget(chkDownload);
|
||||
|
||||
QCheckBox *chkDecompress = new QCheckBox(tr("Decompress"));
|
||||
chkDecompress->setEnabled(flags & UpdateInterface::UPDFLG_Decompress);
|
||||
chkDecompresses << chkDecompress;
|
||||
layout2->addWidget(chkDecompress);
|
||||
|
||||
QCheckBox *chkInstall = new QCheckBox(tr("Install"));
|
||||
chkInstall->setEnabled(flags & UpdateInterface::UPDFLG_AsyncInstall);
|
||||
chkInstalls << chkInstall;
|
||||
layout2->addWidget(chkInstall);
|
||||
|
||||
QSpacerItem *hsp2 = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||
layout2->addItem(hsp2);
|
||||
|
||||
grpAssetsLayout->addLayout(layout2);
|
||||
|
||||
QGridLayout *layout3 = new QGridLayout();
|
||||
|
||||
QCheckBox *chkCopy = new QCheckBox(tr("Copy"));
|
||||
chkCopy->setEnabled(flags & UpdateInterface::UPDFLG_CopyDest);
|
||||
chkCopies << chkCopy;
|
||||
layout3->addWidget(chkCopy, 0, 0);
|
||||
|
||||
QLabel *lblCopyFilter = new QLabel(tr("Filter"));
|
||||
lblCopyFilter->setEnabled(flags & UpdateInterface::UPDFLG_CopyDest);
|
||||
lblCopyFilters << lblCopyFilter;
|
||||
layout3->addWidget(lblCopyFilter, 0, 1);
|
||||
|
||||
QComboBox *cboCopyFilterType = new QComboBox();
|
||||
cboCopyFilterType->setEnabled(!locked);
|
||||
cboCopyFilterType->addItems(UpdateParameters::updateFilterTypeList());
|
||||
cboCopyFilterTypes << cboCopyFilterType;
|
||||
layout3->addWidget(cboCopyFilterType, 0, 2);
|
||||
|
||||
QLineEdit *leCopyFilter = new QLineEdit();
|
||||
leCopyFilter->setEnabled(flags & UpdateInterface::UPDFLG_CopyDest && (!locked));
|
||||
leCopyFilters << leCopyFilter;
|
||||
layout3->addWidget(leCopyFilter, 0, 3);
|
||||
|
||||
connect(leCopyFilter, &QLineEdit::editingFinished, [=]() {
|
||||
QRegularExpression re(leCopyFilter->text());
|
||||
leCopyFilter->setStyleSheet((re.isValid() ? "QLineEdit { color : black; }" : "QLineEdit { color : red; }"));
|
||||
});
|
||||
|
||||
connect(cboCopyFilterType, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](const int index) {
|
||||
if (index == UpdateParameters::UFT_None) {
|
||||
leCopyFilter->setEnabled(false);
|
||||
leCopyFilter->setText("");
|
||||
}
|
||||
else
|
||||
leCopyFilter->setEnabled(!locked);
|
||||
});
|
||||
|
||||
QLabel *lblSubFolder = new QLabel(tr("Sub folder"));
|
||||
lblSubFolder->setEnabled(flags & UpdateInterface::UPDFLG_CopyDest);
|
||||
lblSubFolders << lblSubFolder;
|
||||
layout3->addWidget(lblSubFolder, 1, 1);
|
||||
|
||||
QLineEdit *leSubFolder = new QLineEdit();
|
||||
leSubFolder->setEnabled(flags & UpdateInterface::UPDFLG_CopyDest && (!locked));
|
||||
leSubFolders << leSubFolder;
|
||||
layout3->addWidget(leSubFolder, 1, 2, 1, 2);
|
||||
|
||||
grpAssetsLayout->addLayout(layout3);
|
||||
}
|
||||
|
||||
ui->grpAssets->setLayout(grpAssetsLayout);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=]() {
|
||||
QDialog::accept();
|
||||
});
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, [=](QAbstractButton * button) {
|
||||
if (ui->buttonBox->standardButton(button) == QDialogButtonBox::RestoreDefaults) {
|
||||
factories->resetRunParams(name);
|
||||
update();
|
||||
}
|
||||
else if (ui->buttonBox->standardButton(button) == QDialogButtonBox::Discard) {
|
||||
QDialog::reject();
|
||||
}
|
||||
else if (ui->buttonBox->standardButton(button) == QDialogButtonBox::Save) {
|
||||
runParams->data.updateRelease = ui->cboReleases->currentText();
|
||||
|
||||
for (int i = 0; i < runParams->data.assets.size(); i++) {
|
||||
UpdateParameters::AssetParams &ap = runParams->data.assets[i];
|
||||
|
||||
if (!(ap.flags & UpdateInterface::UPDFLG_Locked)) {
|
||||
ap.filterType = (UpdateParameters::UpdateFilterType)cboAssetFilterTypes.at(i)->currentIndex();
|
||||
ap.filter = leAssetFilters.at(i)->text();
|
||||
ap.copyFilterType = (UpdateParameters::UpdateFilterType)cboCopyFilterTypes.at(i)->currentIndex();
|
||||
ap.copyFilter = leCopyFilters.at(i)->text();
|
||||
ap.destSubDir = leSubFolders.at(i)->text();
|
||||
}
|
||||
|
||||
chkDownloads.at(i)->isChecked() ? ap.flags |= UpdateInterface::UPDFLG_Download : ap.flags &= ~UpdateInterface::UPDFLG_Download;
|
||||
chkDecompresses.at(i)->isChecked() ? ap.flags |= UpdateInterface::UPDFLG_Decompress :ap.flags &= ~UpdateInterface::UPDFLG_Decompress;
|
||||
chkInstalls.at(i)->isChecked() ? ap.flags |= UpdateInterface::UPDFLG_AsyncInstall : ap.flags &= ~UpdateInterface::UPDFLG_AsyncInstall;
|
||||
chkCopies.at(i)->isChecked() ? ap.flags |= UpdateInterface::UPDFLG_CopyDest : ap.flags &= ~UpdateInterface::UPDFLG_CopyDest;
|
||||
ui->chkDelDownload->isChecked() ? ap.flags |= UpdateInterface::UPDFLG_DelDownload : ap.flags &= ~UpdateInterface::UPDFLG_DelDownload;
|
||||
ui->chkDelDecompress->isChecked() ? ap.flags |= UpdateInterface::UPDFLG_DelDecompress : ap.flags &= ~UpdateInterface::UPDFLG_DelDecompress;
|
||||
}
|
||||
|
||||
emit changed(idx);
|
||||
}
|
||||
});
|
||||
|
||||
update();
|
||||
|
||||
QTimer::singleShot(50, this, [=]() {
|
||||
adjustSize();
|
||||
});
|
||||
}
|
||||
|
||||
UpdateOptionsDialog::~UpdateOptionsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void UpdateOptionsDialog::update()
|
||||
{
|
||||
ui->cboReleases->setCurrentText(runParams->data.updateRelease);
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (const UpdateParameters::AssetParams &ap, runParams->data.assets) {
|
||||
cboAssetFilterTypes.at(i)->setCurrentIndex((int)ap.filterType);
|
||||
leAssetFilters.at(i)->setText(ap.filter);
|
||||
|
||||
chkDownloads.at(i)->setChecked(ap.flags & UpdateInterface::UPDFLG_Download);
|
||||
chkDecompresses.at(i)->setChecked(ap.flags & UpdateInterface::UPDFLG_Decompress);
|
||||
chkInstalls.at(i)->setChecked(ap.flags & UpdateInterface::UPDFLG_AsyncInstall);
|
||||
|
||||
chkCopies.at(i)->setChecked(ap.flags & UpdateInterface::UPDFLG_CopyDest);
|
||||
cboCopyFilterTypes.at(i)->setCurrentIndex((int)ap.copyFilterType);
|
||||
leCopyFilters.at(i)->setText(ap.copyFilter);
|
||||
leSubFolders.at(i)->setText(ap.destSubDir);
|
||||
|
||||
ui->chkDelDownload->setChecked(ap.flags & UpdateInterface::UPDFLG_DelDownload);
|
||||
ui->chkDelDecompress->setChecked(ap.flags & UpdateInterface::UPDFLG_DelDecompress);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -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 "updateinterface.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QVector>
|
||||
|
||||
namespace Ui {
|
||||
class UpdateOptionsDialog;
|
||||
}
|
||||
|
||||
class QAbstractButton;
|
||||
|
||||
class UpdateOptionsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UpdateOptionsDialog(QWidget * parent, UpdateFactories * factories, const int idx);
|
||||
virtual ~UpdateOptionsDialog();
|
||||
|
||||
signals:
|
||||
void changed(int index);
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
|
||||
private:
|
||||
Ui::UpdateOptionsDialog *ui;
|
||||
const UpdateFactories *factories;
|
||||
const int idx;
|
||||
const QString name;
|
||||
const UpdateParameters *dfltParams;
|
||||
UpdateParameters *runParams;
|
||||
|
||||
QVector<QComboBox *> cboAssetFilterTypes;
|
||||
QVector<QLineEdit *> leAssetFilters;
|
||||
QVector<QCheckBox *> chkDownloads;
|
||||
QVector<QCheckBox *> chkDecompresses;
|
||||
QVector<QCheckBox *> chkInstalls;
|
||||
QVector<QCheckBox *> chkCopies;
|
||||
QVector<QLabel *> lblCopyFilters;
|
||||
QVector<QComboBox *> cboCopyFilterTypes;
|
||||
QVector<QLineEdit *> leCopyFilters;
|
||||
QVector<QLabel *> lblSubFolders;
|
||||
QVector<QLineEdit *> leSubFolders;
|
||||
};
|
||||
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UpdateOptionsDialog</class>
|
||||
<widget class="QDialog" name="UpdateOptionsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>677</width>
|
||||
<height>393</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Advanced Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpRelease">
|
||||
<property name="title">
|
||||
<string>Release</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnForget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Clear the last updated release information</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Forget</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cboReleases"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblCurrentRelease">
|
||||
<property name="text">
|
||||
<string>Current</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblUpdateToRelease">
|
||||
<property name="text">
|
||||
<string>Update to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leCurrent">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpAssets">
|
||||
<property name="title">
|
||||
<string>Assets</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpGeneral">
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkDelDownload">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete downloads</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkDelDecompress">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete decompressions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>286</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Discard|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 "updates.h"
|
||||
#include "updateinterface.h"
|
||||
#include "updatesdialog.h"
|
||||
#include "progressdialog.h"
|
||||
#include "progresswidget.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
Updates::Updates(QWidget * parent, UpdateFactories * updateFactories) :
|
||||
QWidget(parent),
|
||||
factories(updateFactories)
|
||||
{
|
||||
}
|
||||
|
||||
Updates::~Updates()
|
||||
{
|
||||
}
|
||||
|
||||
void Updates::autoUpdates()
|
||||
{
|
||||
if (g.updateCheckFreq() == AppData::UPDATE_CHECK_MANUAL)
|
||||
return;
|
||||
|
||||
if (g.lastUpdateCheck().trimmed().isEmpty())
|
||||
g.lastUpdateCheck(QDateTime::currentDateTime().addDays(-60).toString(Qt::ISODate));
|
||||
|
||||
QDateTime dt = QDateTime::fromString(g.lastUpdateCheck(), Qt::ISODate);
|
||||
|
||||
if (g.updateCheckFreq() == AppData::UPDATE_CHECK_DAILY)
|
||||
dt = dt.addDays(1);
|
||||
else if (g.updateCheckFreq() == AppData::UPDATE_CHECK_WEEKLY)
|
||||
dt = dt.addDays(7);
|
||||
else if (g.updateCheckFreq() == AppData::UPDATE_CHECK_MONTHLY)
|
||||
dt = dt.addDays(30);
|
||||
|
||||
if (dt > QDateTime::currentDateTime().toLocalTime()) {
|
||||
qDebug() << "Update next due:" << dt.toString(Qt::ISODate);
|
||||
return;
|
||||
}
|
||||
|
||||
g.lastUpdateCheck(QDateTime::currentDateTime().toString(Qt::ISODate));
|
||||
|
||||
if (!factories->updatesAvailable())
|
||||
return;
|
||||
|
||||
if (QMessageBox::question(parentWidget(), CPN_STR_APP_NAME % ": " % tr("Checking for Updates"),
|
||||
tr("One or more updates are available. Update now?"),
|
||||
(QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
factories->resetAllRunParams();
|
||||
factories->autoUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void Updates::manualUpdates()
|
||||
{
|
||||
factories->resetAllRunParams();
|
||||
UpdatesDialog *dlg = new UpdatesDialog(this, factories);
|
||||
|
||||
if (dlg->exec()) {
|
||||
ProgressDialog progressDialog(this, tr("Update Components"), CompanionIcon("fuses.png"), true);
|
||||
progressDialog.progress()->lock(true);
|
||||
progressDialog.progress()->setInfo(tr("Starting..."));
|
||||
bool ok = factories->manualUpdate(progressDialog.progress());
|
||||
progressDialog.progress()->lock(false);
|
||||
progressDialog.progress()->setInfo(tr("Finished %1").arg(ok ? tr("successfully") : tr("with errors")));
|
||||
progressDialog.exec();
|
||||
}
|
||||
|
||||
delete dlg;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
* 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
|
||||
@@ -18,26 +19,24 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _RELEASENOTESDIALOG_H_
|
||||
#define _RELEASENOTESDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "helpers.h"
|
||||
#include <QtCore>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class HtmlDialog;
|
||||
}
|
||||
class UpdateFactories;
|
||||
|
||||
class ReleaseNotesDialog : public QDialog
|
||||
class Updates : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ReleaseNotesDialog(QWidget *parent = 0);
|
||||
~ReleaseNotesDialog();
|
||||
explicit Updates(QWidget * parent, UpdateFactories * updateFactories);
|
||||
virtual ~Updates();
|
||||
|
||||
void autoUpdates();
|
||||
void manualUpdates();
|
||||
|
||||
private:
|
||||
Ui::HtmlDialog * ui;
|
||||
UpdateFactories *factories;
|
||||
};
|
||||
|
||||
#endif // _RELEASENOTESDIALOG_H_
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 "updatesdcard.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
UpdateSDCard::UpdateSDCard(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
{
|
||||
setName("SD Card");
|
||||
setRepo(QString(GH_REPOS_EDGETX).append("/edgetx-sdcard"));
|
||||
|
||||
dfltParams->data.flags = UPDFLG_Common | UPDFLG_Locked;
|
||||
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
ap.filterType = UpdateParameters::UFT_Startswith;
|
||||
ap.filter = QString("%1-").arg(fwFlavour);
|
||||
ap.maxExpected = 1;
|
||||
ap.flags = dfltParams->data.flags | UPDFLG_CopyStructure;
|
||||
}
|
||||
|
||||
bool UpdateSDCard::flagAssets()
|
||||
{
|
||||
progressMessage(tr("Flagging assets"));
|
||||
/*
|
||||
{
|
||||
"targets": [
|
||||
["Flysky NV14", "nv14-", "nv14"],
|
||||
["FrSky Horus X10", "x10-", "horus"],
|
||||
*/
|
||||
|
||||
const QString mappingfile = "sdcard.json";
|
||||
|
||||
if (!downloadTextFileToBuffer(mappingfile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument *json = new QJsonDocument();
|
||||
|
||||
if (!convertDownloadToJson(json)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateParameters::AssetParams ap = runParams->data.assets.at(0);
|
||||
|
||||
QRegularExpression filter(UpdateParameters::buildFilterPattern(ap.filterType, ap.filter), QRegularExpression::CaseInsensitiveOption);
|
||||
bool found = false;
|
||||
QString sdimage;
|
||||
|
||||
if (json->isObject()) {
|
||||
const QJsonObject &obj = json->object();
|
||||
|
||||
if (obj.value("targets").isArray()) {
|
||||
const QJsonArray &t = obj.value("targets").toArray();
|
||||
|
||||
foreach (const QJsonValue &v, t) {
|
||||
|
||||
if (v.isArray()) {
|
||||
const QJsonArray &i = v.toArray();
|
||||
if (i.size() > 2) {
|
||||
if (i.at(1).toString().contains(filter)) {
|
||||
sdimage = i.at(2).toString();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
reportProgress(tr("Radio flavour %1 not listed in %2").arg(fwFlavour).arg(mappingfile), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
delete json;
|
||||
|
||||
if (!getSetAssets(ap.flags, UpdateParameters::UFT_Startswith, sdimage, ap.maxExpected, ap.destSubDir, ap.copyFilterType, ap.copyFilter))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
class UpdateSDCard : public UpdateInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateSDCard)
|
||||
|
||||
public:
|
||||
|
||||
explicit UpdateSDCard(QWidget * parent);
|
||||
virtual ~UpdateSDCard() {}
|
||||
|
||||
protected:
|
||||
virtual bool flagAssets() override;
|
||||
};
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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 "updatesdialog.h"
|
||||
#include "ui_updatesdialog.h"
|
||||
#include "updateoptionsdialog.h"
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QMap>
|
||||
#include <QFileDialog>
|
||||
#include <QTimer>
|
||||
|
||||
UpdatesDialog::UpdatesDialog(QWidget * parent, UpdateFactories * factories) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::UpdatesDialog),
|
||||
factories(factories)
|
||||
{
|
||||
// downloading the release meta data takes a few seconds for each component so display progress
|
||||
QDialog *status = new QDialog(parent);
|
||||
status->setWindowTitle(tr("Progress"));
|
||||
QVBoxLayout *layout = new QVBoxLayout(status);
|
||||
QLabel *msg = new QLabel(status);
|
||||
msg->setFixedWidth(400);
|
||||
msg->setContentsMargins(50, 50, 50, 50);
|
||||
layout->addWidget(msg);
|
||||
status->show();
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->leDownloadDir->setText(g.downloadDir());
|
||||
|
||||
connect(ui->chkDecompressUseDwnld, &QCheckBox::stateChanged, [=](const int checked) {
|
||||
if (!checked) {
|
||||
ui->leDecompressDir->setText(g.decompressDir());
|
||||
ui->leDecompressDir->setEnabled(true);
|
||||
ui->btnDecompressSelect->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
ui->leDecompressDir->setText(g.downloadDir());
|
||||
ui->leDecompressDir->setEnabled(false);
|
||||
ui->btnDecompressSelect->setEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
ui->chkDecompressUseDwnld->setChecked(!g.decompressUseDwnld());
|
||||
ui->chkDecompressUseDwnld->setChecked(g.decompressUseDwnld());
|
||||
|
||||
connect(ui->chkUpdateUseSD, &QCheckBox::stateChanged, [=](const int checked) {
|
||||
if (!checked) {
|
||||
ui->leUpdateDir->setText(g.updateDir());
|
||||
ui->leUpdateDir->setEnabled(true);
|
||||
ui->btnUpdateSelect->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
ui->leUpdateDir->setText(g.currentProfile().sdPath());
|
||||
ui->leUpdateDir->setEnabled(false);
|
||||
ui->btnUpdateSelect->setEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
ui->chkUpdateUseSD->setChecked(!g.updateUseSD());
|
||||
ui->chkUpdateUseSD->setChecked(g.updateUseSD());
|
||||
|
||||
connect(ui->btnDownloadSelect, &QPushButton::clicked, [=]() {
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this,tr("Select your download folder"), g.downloadDir());
|
||||
if (!dirPath.isEmpty()) {
|
||||
ui->leDownloadDir->setText(dirPath);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnDecompressSelect, &QPushButton::clicked, [=]() {
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this,tr("Select your decompress folder"), g.decompressDir());
|
||||
if (!dirPath.isEmpty()) {
|
||||
ui->leDecompressDir->setText(dirPath);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnUpdateSelect, &QPushButton::clicked, [=]() {
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this,tr("Select your update destination folder"), g.updateDir());
|
||||
if (!dirPath.isEmpty()) {
|
||||
ui->leUpdateDir->setText(dirPath);
|
||||
}
|
||||
});
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
|
||||
QGridLayout *grid = new QGridLayout();
|
||||
|
||||
QLabel *h1 = new QLabel();
|
||||
grid->addWidget(h1, row, col++);
|
||||
|
||||
QLabel *h2 = new QLabel(tr("Name"));
|
||||
grid->addWidget(h2, row, col++);
|
||||
|
||||
QLabel *h3 = new QLabel(tr("Channel"));
|
||||
grid->addWidget(h3, row, col++);
|
||||
|
||||
QLabel *h4 = new QLabel(tr("Current Release"));
|
||||
grid->addWidget(h4, row, col++);
|
||||
|
||||
QLabel *h5 = new QLabel(tr("Update Release"));
|
||||
grid->addWidget(h5, row, col++);
|
||||
|
||||
col++; // options button
|
||||
|
||||
QSpacerItem * spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||
grid->addItem(spacer, row, col++);
|
||||
|
||||
QMapIterator<QString, int> it(factories->sortedComponentsList());
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
int i = it.value();
|
||||
|
||||
const QString name = it.key();
|
||||
|
||||
if (g.component[i].checkForUpdate()) {
|
||||
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(name));
|
||||
grid->addWidget(chkUpdate[i], row, col++);
|
||||
grid->setAlignment(chkUpdate[i], Qt::AlignHCenter);
|
||||
|
||||
QLabel *lblName = new QLabel(name);
|
||||
grid->addWidget(lblName, row, col++);
|
||||
|
||||
QLabel *lblRC = new QLabel(ComponentData::releaseChannelsList().at(g.component[i].releaseChannel()));
|
||||
grid->addWidget(lblRC, row, col++);
|
||||
|
||||
lblCurrentRel[i] = new QLabel(factories->currentRelease(name));
|
||||
grid->addWidget(lblCurrentRel[i], row, col++);
|
||||
|
||||
lblUpdateRel[i] = new QLabel(factories->updateRelease(name));
|
||||
grid->addWidget(lblUpdateRel[i], row, col++);
|
||||
|
||||
btnOptions[i] = new QPushButton(tr("Options"));
|
||||
connect(btnOptions[i], &QPushButton::clicked, [=]() {
|
||||
UpdateOptionsDialog *dlg = new UpdateOptionsDialog(this, factories, i);
|
||||
connect(dlg, &UpdateOptionsDialog::changed, [=](const int i) {
|
||||
QString name = g.component[i].name();
|
||||
lblCurrentRel[i]->setText(factories->currentRelease(name));
|
||||
lblUpdateRel[i]->setText(factories->updateRelease(name));
|
||||
});
|
||||
dlg->exec();
|
||||
dlg->deleteLater();
|
||||
});
|
||||
|
||||
grid->addWidget(btnOptions[i], row, col++);
|
||||
}
|
||||
}
|
||||
|
||||
ui->grpComponents->setLayout(grid);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=]() {
|
||||
QMapIterator<QString, int> it(factories->sortedComponentsList());
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
int i = it.value();
|
||||
|
||||
if (g.component[i].checkForUpdate()) {
|
||||
if (chkUpdate[i]->isChecked()) {
|
||||
const QString name = it.key();
|
||||
UpdateParameters *runParams = factories->getRunParams(name);
|
||||
runParams->data.flags |= UpdateInterface::UPDFLG_Update;
|
||||
runParams->data.downloadDir = ui->leDownloadDir->text();
|
||||
runParams->data.decompressUseDwnld = ui->chkDecompressUseDwnld->isChecked();
|
||||
runParams->data.decompressDir = ui->leDecompressDir->text();
|
||||
runParams->data.updateUseSD = ui->chkUpdateUseSD->isChecked();
|
||||
runParams->data.updateDir = ui->leUpdateDir->text();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
});
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, [=]() {
|
||||
QDialog::reject();
|
||||
});
|
||||
|
||||
ui->leDownloadDir->home(false);
|
||||
|
||||
status->hide();
|
||||
status->deleteLater();
|
||||
|
||||
QTimer::singleShot(50, this, [=]() {
|
||||
adjustSize();
|
||||
});
|
||||
}
|
||||
|
||||
UpdatesDialog::~UpdatesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
* 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
|
||||
@@ -18,35 +19,39 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FWPREFERENCESDIALOG_H_
|
||||
#define _FWPREFERENCESDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include "updateinterface.h"
|
||||
#include "appdata.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QCheckBox>
|
||||
#include "eeprominterface.h"
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace Ui {
|
||||
class FirmwarePreferencesDialog;
|
||||
class UpdatesDialog;
|
||||
}
|
||||
|
||||
class Joystick;
|
||||
|
||||
class FirmwarePreferencesDialog : public QDialog
|
||||
class UpdatesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FirmwarePreferencesDialog(QWidget *parent = 0);
|
||||
~FirmwarePreferencesDialog();
|
||||
UpdatesDialog(QWidget * parent, UpdateFactories * factories);
|
||||
virtual ~UpdatesDialog();
|
||||
|
||||
private:
|
||||
Ui::FirmwarePreferencesDialog *ui;
|
||||
void initSettings();
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void on_fw_dnld_clicked();
|
||||
void on_sd_dnld_clicked();
|
||||
void on_checkFWUpdates_clicked();
|
||||
|
||||
private:
|
||||
Ui::UpdatesDialog *ui;
|
||||
const UpdateFactories *factories;
|
||||
|
||||
QCheckBox *chkUpdate[MAX_COMPONENTS];
|
||||
QLabel *lblCurrentRel[MAX_COMPONENTS];
|
||||
QLabel *lblUpdateRel[MAX_COMPONENTS];
|
||||
QPushButton *btnOptions[MAX_COMPONENTS];
|
||||
};
|
||||
|
||||
#endif // _FWPREFERENCESDIALOG_H_
|
||||
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UpdatesDialog</class>
|
||||
<widget class="QDialog" name="UpdatesDialog">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>525</width>
|
||||
<height>289</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Process Updates</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpFolders">
|
||||
<property name="title">
|
||||
<string>Folders</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblDownloadDir">
|
||||
<property name="text">
|
||||
<string>Download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leDownloadDir"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lblUpdateDir">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="chkDecompressUseDwnld">
|
||||
<property name="text">
|
||||
<string>Create sub-folders in Download folder</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="leDecompressDir">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblDecompressDir">
|
||||
<property name="text">
|
||||
<string>Decompress</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="chkUpdateUseSD">
|
||||
<property name="text">
|
||||
<string>Use Radio Profile SD structure</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="leUpdateDir">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="btnUpdateSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="btnDecompressSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnDownloadSelect">
|
||||
<property name="text">
|
||||
<string>Select folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="grpComponents">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Components</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>UpdatesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>UpdatesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#include "updatesounds.h"
|
||||
|
||||
UpdateSounds::UpdateSounds(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
{
|
||||
setName("Sounds");
|
||||
setRepo(QString(GH_REPOS_EDGETX).append("/edgetx-sdcard-sounds"));
|
||||
|
||||
/*
|
||||
file: sounds.json
|
||||
[
|
||||
{
|
||||
"language": "cs_CZ",
|
||||
"name": "Czech Female",
|
||||
"description": "Czech Female Voice (cs-CZ-Vlasta)",
|
||||
"directory": "cz"
|
||||
},
|
||||
|
||||
TODO support multiple language sub variants
|
||||
// eg edgetx-sdcard-sounds-en_gb-libby-2.7.0.zip
|
||||
ap.filter = QString("^edgetx-sdcard-sounds-%1").arg(language); //return all variants of each language
|
||||
*/
|
||||
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
// only supports default for each language
|
||||
// eg edgetx-sdcard-sounds-en-2.7.0.zip
|
||||
ap.filterType = UpdateParameters::UFT_Startswith;
|
||||
ap.filter = QString("edgetx-sdcard-sounds-%1-").arg(language);
|
||||
// if user changes filter then more than one could be returned
|
||||
//ap.maxExpected = 1;
|
||||
ap.flags = dfltParams->data.flags | UPDFLG_CopyStructure;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "updateinterface.h"
|
||||
|
||||
class UpdateSounds : public UpdateInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateSounds)
|
||||
|
||||
public:
|
||||
|
||||
explicit UpdateSounds(QWidget * parent);
|
||||
virtual ~UpdateSounds() {}
|
||||
|
||||
};
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
* 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
|
||||
@@ -18,32 +19,18 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _RELEASENOTESFIRMWAREDIALOG_H_
|
||||
#define _RELEASENOTESFIRMWAREDIALOG_H_
|
||||
|
||||
#include <QDialog>
|
||||
#include "updatethemes.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "downloaddialog.h"
|
||||
|
||||
namespace Ui {
|
||||
class HtmlDialog;
|
||||
}
|
||||
|
||||
class ReleaseNotesFirmwareDialog : public QDialog
|
||||
UpdateThemes::UpdateThemes(QWidget * parent) :
|
||||
UpdateInterface(parent)
|
||||
{
|
||||
Q_OBJECT
|
||||
setName("Themes");
|
||||
setRepo(QString(GH_REPOS_EDGETX).append("/themes"));
|
||||
|
||||
public:
|
||||
explicit ReleaseNotesFirmwareDialog(QWidget *parent, const QString & rnurl);
|
||||
~ReleaseNotesFirmwareDialog();
|
||||
|
||||
private:
|
||||
Ui::HtmlDialog *ui;
|
||||
QNetworkAccessManager *manager;
|
||||
|
||||
private slots:
|
||||
void replyFinished(QNetworkReply * reply);
|
||||
|
||||
};
|
||||
|
||||
#endif // _RELEASENOTESFIRMWAREDIALOG_H_
|
||||
UpdateParameters::AssetParams &ap = dfltParams->addAsset();
|
||||
ap.filterType = UpdateParameters::UFT_Startswith;
|
||||
ap.filter = "edgetx-themes";
|
||||
ap.maxExpected = 1;
|
||||
ap.flags = dfltParams->data.flags | UPDFLG_CopyStructure;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "updateinterface.h"
|
||||
|
||||
class UpdateThemes : public UpdateInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateThemes)
|
||||
|
||||
public:
|
||||
|
||||
explicit UpdateThemes(QWidget * parent);
|
||||
virtual ~UpdateThemes() {}
|
||||
|
||||
};
|
||||