[Companion] Implement application settings import and export via GUI and CLI.

This commit is contained in:
Max Paperno
2018-06-29 20:18:35 -04:00
parent 988c837011
commit 63476c03f3
6 changed files with 232 additions and 20 deletions
+131 -20
View File
@@ -22,6 +22,7 @@
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QSplashScreen>
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
#include <SDL.h>
@@ -36,6 +37,7 @@
#include "simulatorinterface.h"
#include "storage.h"
#include "translations.h"
#include "helpers.h"
#ifdef __APPLE__
#include <QProxyStyle>
@@ -52,6 +54,84 @@ class MyProxyStyle : public QProxyStyle
};
#endif
void importError()
{
QMessageBox::critical(nullptr, CPN_STR_APP_NAME, QCoreApplication::translate("Companion", "The saved settings could not be imported, please try again or continue with current settings."), QMessageBox::Ok, 0);
}
void checkSettingsImport(bool force = false)
{
QString previousVersion;
bool found;
if (!(found = g.findPreviousVersionSettings(&previousVersion))) {
found = QDir(CPN_SETTINGS_BACKUP_DIR).entryList(QStringList({"*.ini"}), QDir::Files).size() > 0;
}
if (!found && !force)
return;
const QString impFileBtn = QCoreApplication::translate("Companion", "Import from File");
const QString impPrevBtn = QCoreApplication::translate("Companion", "Import from v%1").arg(previousVersion);
const QString impNoneBtn = QCoreApplication::translate("Companion", "Do not import");
QString msg;
if (previousVersion.isEmpty()) {
if (found)
msg = QCoreApplication::translate("Companion", "We have found possible Companion settings backup file(s).\nDo you want to import settings from a file?");
else
msg = QCoreApplication::translate("Companion", "Import settings from a file, or start with current values.");
}
else {
msg = QCoreApplication::translate("Companion", "We have found existing settings for Companion version: %1.\nDo you want to import them?\n\n" \
"If you have a settings backup file, you may import that instead.").arg(previousVersion);
}
const int ret = QMessageBox::question(nullptr, CPN_STR_APP_NAME, msg, impNoneBtn, impFileBtn, (previousVersion.isEmpty() ? QString() : impPrevBtn), 0, 0);
if (!ret)
return;
// Import from previous version
if (ret == 2) {
if (!g.importSettings(previousVersion)) {
// very unlikely, but just in case of unexpected error, restart the import
importError();
checkSettingsImport();
}
return;
}
// Import from file
bool err = false;
QString impFile = CPN_SETTINGS_BACKUP_DIR;
impFile = QFileDialog::getOpenFileName(nullptr, QCoreApplication::translate("Companion", "Select %1:").arg(CPN_STR_APP_SETTINGS_FILES), impFile, CPN_STR_APP_SETTINGS_FILTER);
if (!impFile.isEmpty() && QFileInfo(impFile).isReadable()) {
QSettings fromSettings(impFile, QSettings::IniFormat);
if (g.importSettings(&fromSettings)) {
return;
}
else {
importError();
err = true;
}
}
// Restart the import prompt if user cancelled the file select dialog but we do have previous settings, or if we had a file import error.
if (err || !previousVersion.isEmpty())
checkSettingsImport();
}
void printHelpText()
{
printf(qPrintable(QString(APP_COMPANION % " v%s\n\n")), VERSION);
const char tmpl[] = " %s \t %s\n";
printf(tmpl, "--export", QCoreApplication::translate("Companion", "Save application settings to file...").toUtf8().constData());
printf(tmpl, "--import", QCoreApplication::translate("Companion", "Load application settings from file or previous version...").toUtf8().constData());
printf(tmpl, "--defaults", QCoreApplication::translate("Companion", "Reset ALL application settings to default and remove radio profiles...").toUtf8().constData());
printf(tmpl, "--quit ", QCoreApplication::translate("Companion", "Exit before settings initialization and application startup.").toUtf8().constData());
printf(tmpl, "--version", QCoreApplication::translate("Companion", "Print version number and exit.").toUtf8().constData());
printf(tmpl, "--help|-h", QCoreApplication::translate("Companion", "Print this help text.").toUtf8().constData());
fflush(stdout);
}
int main(int argc, char *argv[])
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
@@ -65,6 +145,19 @@ int main(int argc, char *argv[])
app.setOrganizationDomain(COMPANY_DOMAIN);
app.setAttribute(Qt::AA_DontShowIconsInMenus, false);
const QStringList args(QApplication::arguments());
if (args.contains("--help") || args.contains("-h") || args.contains("/?")) {
printHelpText();
exit(0);
}
if (args.contains("--version")) {
printf("%s\n", VERSION);
fflush(stdout);
exit(0);
}
Q_INIT_RESOURCE(companion);
if (AppDebugMessageHandler::instance())
@@ -72,28 +165,45 @@ int main(int argc, char *argv[])
CustomDebug::setFilterRules();
if (!g.hasCurrentSettings()) {
QString previousVersion;
if (g.findPreviousVersionSettings(&previousVersion)) {
QMessageBox msgBox;
msgBox.setText(QCoreApplication::translate("Companion", "We have found existing settings for Companion version: %1.\nDo you want to import them?").arg(previousVersion));
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
int ret = msgBox.exec();
// handle settings export/import/reset via CLI
if (ret == QMessageBox::Yes)
g.importSettings(previousVersion);
bool doExport = args.contains("--export");
bool doImport = args.contains("--import");
bool doReset = args.contains("--defaults");
if (doExport)
Helpers::exportAppSettings();
if (doReset) {
char ok;
printf("%s [Y/N] ", QCoreApplication::translate("Companion", "Reset ALL application settings to default values and remove radio profiles, are you sure?").toUtf8().constData());
std::cin >> ok;
if (ok != 'Y' && ok != 'y')
exit(0);
if (!doExport) {
printf("%s [Y/N] ", QCoreApplication::translate("Companion", "Would you like to perform a backup first?").toUtf8().constData());
std::cin >> ok;
if (ok == 'Y' || ok == 'y')
Helpers::exportAppSettings();
}
g.resetAllSettings();
g.storeAllSettings();
std::cout << QCoreApplication::translate("Companion", "Application settings were reset and saved.").toUtf8().constData() << std::endl;
}
g.init();
QStringList strl = QApplication::arguments();
if (strl.contains("--version")) {
printf("%s\n", VERSION);
fflush(stdout);
if (doImport)
checkSettingsImport(true);
// give option to quit before settings init
if (args.contains("--quit"))
exit(0);
}
// end CLI handling
if (!doImport && g.isFirstUse())
checkSettingsImport(false);
g.init();
QFile dbgLog;
if (AppDebugMessageHandler::instance() && g.appDebugLog() && !g.appLogsDir().isEmpty() && QDir().mkpath(g.appLogsDir())) {
@@ -127,9 +237,10 @@ int main(int argc, char *argv[])
registerOpenTxFirmwares();
SimulatorLoader::registerSimulators();
if (g.profile[g.id()].fwType().isEmpty()){
g.profile[g.id()].fwType(Firmware::getDefaultVariant()->getId());
g.profile[g.id()].fwName("");
Profile & profile = g.currentProfile();
if (profile.fwType().isEmpty()){
profile.fwType(Firmware::getDefaultVariant()->getId());
profile.fwName("");
}
QString splashScreen;
+4
View File
@@ -69,6 +69,10 @@
#define EEPE_EEPROM_FILE_HEADER "EEPE EEPROM FILE"
#define EEPE_MODEL_FILE_HEADER "EEPE MODEL FILE"
#define CPN_STR_APP_SETTINGS QCoreApplication::translate("Companion", "Application Settings")
#define CPN_STR_APP_SETTINGS_FILES CPN_STR_APP_SETTINGS % " " % CPN_STR_FILES
#define CPN_STR_APP_SETTINGS_FILTER CPN_STR_APP_SETTINGS_FILES % " (*.ini)"
#define CPN_STR_SW_INDICATOR_UP QCoreApplication::translate("RawSwitch", "\xE2\x86\x91") // Switch up position indicator: Up arrow, or similar.
#define CPN_STR_SW_INDICATOR_DN QCoreApplication::translate("RawSwitch", "\xE2\x86\x93") // Switch down position indicator: Down arrow, or similar.
#define CPN_STR_SW_INDICATOR_NEUT QCoreApplication::translate("RawSwitch", "-") // Switch neutral (middle) position indicator.
+19
View File
@@ -33,6 +33,7 @@
#include "simulatormainwindow.h"
#include "storage/sdcard.h"
#include <QFileDialog>
#include <QLabel>
#include <QMessageBox>
@@ -543,6 +544,24 @@ QStandardItemModel * Helpers::getRawSourceItemModel(const GeneralSettings * cons
return itemModel;
}
void Helpers::exportAppSettings(QWidget * dlgParent)
{
static QString lastExpFile = CPN_SETTINGS_INI_PATH.arg(QDateTime::currentDateTime().toString("dd-MMM-yy"));
const QString expFile = QFileDialog::getSaveFileName(dlgParent, QCoreApplication::translate("Companion", "Select or create a file for exported Settings:"), lastExpFile, CPN_STR_APP_SETTINGS_FILTER);
if (expFile.isEmpty())
return;
lastExpFile = expFile;
QString resultMsg;
if (g.exportSettingsToFile(expFile, resultMsg)) {
QMessageBox::information(dlgParent, CPN_STR_APP_NAME, resultMsg);
return;
}
resultMsg.append("\n" % QCoreApplication::translate("Companion", "Press the 'Retry' button to choose another file."));
if (QMessageBox::warning(dlgParent, CPN_STR_APP_NAME, resultMsg, QMessageBox::Cancel, QMessageBox::Retry) == QMessageBox::Retry)
exportAppSettings(dlgParent);
}
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
{
QString fwId = SimulatorLoader::findSimulatorByFirmwareName(getCurrentFirmware()->getId());
+3
View File
@@ -143,6 +143,9 @@ namespace Helpers
void populateFileComboBox(QComboBox * b, const QSet<QString> & set, const QString & current);
void getFileComboBoxValue(QComboBox * b, char * dest, int length);
void exportAppSettings(QWidget * dlgParent = nullptr);
} // namespace Helpers
// TODO : move globals to Helpers namespace
+71
View File
@@ -1387,6 +1387,9 @@ void MainWindow::retranslateUi(bool showMsg)
trAct(copyProfileAct, tr("Copy Current Radio Profile"), tr("Duplicate current Radio Settings Profile"));
trAct(deleteProfileAct, tr("Delete Current Radio Profile..."), tr("Delete the current Radio Settings Profile"));
trAct(exportSettingsAct, tr("Export Application Settings.."), tr("Save all the current %1 and Simulator settings (including radio profiles) to a file.").arg(CPN_STR_APP_NAME));
trAct(importSettingsAct, tr("Import Application Settings.."), tr("Load %1 and Simulator settings from a prevously exported settings file.").arg(CPN_STR_APP_NAME));
trAct(actTabbedWindows, tr("Tabbed Windows"), tr("Use tabs to arrange open windows."));
trAct(actTileWindows, tr("Tile Windows"), tr("Arrange open windows across all the available space."));
trAct(actCascadeWindows, tr("Cascade Windows"), tr("Arrange all open windows in a stack."));
@@ -1442,6 +1445,9 @@ void MainWindow::createActions()
copyProfileAct = addAct("copy.png", SLOT(copyProfile()));
deleteProfileAct = addAct("clear.png", SLOT(deleteCurrentProfile()));
exportSettingsAct = addAct("saveas.png", SLOT(exportSettings()));
importSettingsAct = addAct("open.png", SLOT(importSettings()));
actTabbedWindows = addAct("", SLOT(setTabbedWindows(bool)), 0, this, SIGNAL(triggered(bool)));
actTileWindows = addAct("", SLOT(tileSubWindows()), 0, mdiArea);
actCascadeWindows = addAct("", SLOT(cascadeSubWindows()), 0, mdiArea);
@@ -1515,6 +1521,9 @@ void MainWindow::createMenus()
settingsMenu->addAction(profilesMenuAct);
settingsMenu->addAction(editSplashAct);
settingsMenu->addAction(burnConfigAct);
settingsMenu->addSeparator();
settingsMenu->addAction(exportSettingsAct);
settingsMenu->addAction(importSettingsAct);
burnMenu = menuBar()->addMenu("");
burnMenu->addAction(writeEepromAct);
@@ -1854,6 +1863,68 @@ void MainWindow::deleteCurrentProfile()
deleteProfile(g.id());
}
void MainWindow::exportSettings()
{
Helpers::exportAppSettings();
}
void MainWindow::importSettings()
{
if (anyChildrenDirty()) {
QMessageBox::warning(this, CPN_STR_APP_NAME, tr("Please save or close all modified files before importing settings"));
return;
}
QString resultMsg = tr("<html>" \
"<p>%1 and Simulator settings can be imported (restored) from a previosly saved export (backup) file. " \
"This will replace current settings with any settings found in the file.</p>" \
"<p>An automatic backup of the current settings will be attempted. But if the current settings are useful then it is recommended that you make a manual backup first.</p>" \
"<p>For best results when importing settings, <b>close any other %1 windows you may have open, and make sure the standalone Simulator application is not running.</p>" \
"<p>Do you wish to continue?</p>" \
"</html>").arg(CPN_STR_APP_NAME);
int ret = QMessageBox::question(this, tr("Confirm Settings Import"), resultMsg);
if (ret != QMessageBox::Yes)
return;
QString impFile = CPN_SETTINGS_BACKUP_DIR;
impFile = QFileDialog::getOpenFileName(this, tr("Select %1:").arg(CPN_STR_APP_SETTINGS_FILES), impFile, CPN_STR_APP_SETTINGS_FILTER);
if (impFile.isEmpty() || !QFileInfo(impFile).isReadable() || QFileInfo(impFile).isExecutable())
return;
// Try a backup first
QString expFile = CPN_SETTINGS_INI_PATH.arg(tr("backup") % " " % QDateTime::currentDateTime().toString("dd-MMM-yy HH-mm"));
if (!g.exportSettingsToFile(expFile, resultMsg)) {
resultMsg.append("\n" % tr("Press the 'Ignore' button to continue anyway."));
if (QMessageBox::warning(this, CPN_STR_APP_NAME, resultMsg, QMessageBox::Cancel, QMessageBox::Ignore) == QMessageBox::Cancel)
return;
expFile.clear();
}
const QString prevLoc = g.locale();
// Do the import
QSettings fromSettings(impFile, QSettings::IniFormat);
if (!g.importSettings(&fromSettings)) {
QMessageBox::critical(this, CPN_STR_APP_NAME, tr("The settings could not be imported."), QMessageBox::Ok, 0);
return;
}
resultMsg = tr("<html>" \
"<p>New settings have been imported from:<br> %1.</p>" \
"<p>%2 will now re-initialize.</p>" \
"<p>Note that you may need to close and restart %2 before some settings like language and icon theme take effect.</p>" \
).arg(impFile).arg(CPN_STR_APP_NAME);
if (!expFile.isEmpty())
resultMsg.append(tr("<p>The previous settings were backed up to:<br> %1</p>").arg(expFile));
resultMsg.append("</html>");
QMessageBox::information(this, CPN_STR_APP_NAME, resultMsg);
g.init();
initWindowOptions();
if (prevLoc != g.locale())
Translations::installTranslators();
onCurrentProfileChanged();
}
QString MainWindow::strippedName(const QString &fullFileName)
{
return QFileInfo(fullFileName).fileName();
+4
View File
@@ -130,6 +130,8 @@ class MainWindow : public QMainWindow
void copyProfile();
void deleteProfile(const int pid);
void deleteCurrentProfile();
void exportSettings();
void importSettings();
void autoClose();
void closeUpdatesWaitDialog();
@@ -221,6 +223,8 @@ class MainWindow : public QMainWindow
QAction *createProfileAct;
QAction *copyProfileAct;
QAction *deleteProfileAct;
QAction *exportSettingsAct;
QAction *importSettingsAct;
QAction *openDocURLAct;
QAction *actTabbedWindows;
QAction *actTileWindows;