[Companion] Add optional logging of all debug output. (#4974)
[opentx.git] / companion / src / apppreferencesdialog.cpp
blob1d8bf7b3b0d75c57500e38f88f70f2d028fd5771
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "apppreferencesdialog.h"
22 #include "ui_apppreferencesdialog.h"
23 #include "mainwindow.h"
24 #include "appdata.h"
25 #include "helpers.h"
26 #include "firmwareinterface.h"
27 #ifdef JOYSTICKS
28 #include "joystick.h"
29 #include "joystickdialog.h"
30 #endif
31 #include <QDesktopServices>
32 #include <QtGui>
34 AppPreferencesDialog::AppPreferencesDialog(QWidget * parent) :
35 QDialog(parent),
36 ui(new Ui::AppPreferencesDialog)
38 ui->setupUi(this);
39 updateLock=false;
40 setWindowIcon(CompanionIcon("apppreferences.png"));
42 initSettings();
43 connect(ui->downloadVerCB, SIGNAL(currentIndexChanged(int)), this, SLOT(baseFirmwareChanged()));
44 connect(ui->opt_appDebugLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings);
45 connect(ui->opt_fwTraceLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings);
46 connect(this, SIGNAL(accepted()), this, SLOT(writeValues()));
48 #if !defined(JOYSTICKS)
49 ui->joystickCB->hide();
50 ui->joystickCB->setDisabled(true);
51 ui->joystickcalButton->hide();
52 ui->joystickChkB->hide();
53 ui->label_11->hide();
54 #endif
56 shrink();
59 AppPreferencesDialog::~AppPreferencesDialog()
61 delete ui;
64 void AppPreferencesDialog::writeValues()
66 g.useCompanionNightlyBuilds(ui->useCompanionNightlyBuilds->isChecked());
67 g.autoCheckApp(ui->autoCheckCompanion->isChecked());
68 g.useFirmwareNightlyBuilds(ui->useFirmwareNightlyBuilds->isChecked());
69 g.autoCheckFw(ui->autoCheckFirmware->isChecked());
70 g.showSplash(ui->showSplash->isChecked());
71 g.simuSW(ui->simuSW->isChecked());
72 g.removeModelSlots(ui->opt_removeBlankSlots->isChecked());
73 g.newModelAction(ui->opt_newMdl_useWizard->isChecked() ? 1 : ui->opt_newMdl_useEditor->isChecked() ? 2 : 0);
74 g.historySize(ui->historySize->value());
75 g.backLight(ui->backLightColor->currentIndex());
76 g.profile[g.id()].volumeGain(round(ui->volumeGain->value() * 10.0));
77 g.libDir(ui->libraryPath->text());
78 g.gePath(ui->ge_lineedit->text());
79 g.embedSplashes(ui->splashincludeCB->currentIndex());
80 g.enableBackup(ui->backupEnable->isChecked());
82 g.appDebugLog(ui->opt_appDebugLog->isChecked());
83 g.fwTraceLog(ui->opt_fwTraceLog->isChecked());
84 g.appLogsDir(ui->appLogsDir->text());
86 if (ui->joystickChkB ->isChecked() && ui->joystickCB->isEnabled()) {
87 g.jsSupport(ui->joystickChkB ->isChecked());
88 g.jsCtrl(ui->joystickCB ->currentIndex());
90 else {
91 g.jsSupport(false);
92 g.jsCtrl(0);
94 g.profile[g.id()].channelOrder(ui->channelorderCB->currentIndex());
95 g.profile[g.id()].defaultMode(ui->stickmodeCB->currentIndex());
96 g.profile[g.id()].renameFwFiles(ui->renameFirmware->isChecked());
97 g.profile[g.id()].burnFirmware(ui->burnFirmware->isChecked());
98 g.profile[g.id()].sdPath(ui->sdPath->text());
99 g.profile[g.id()].pBackupDir(ui->profilebackupPath->text());
100 g.profile[g.id()].penableBackup(ui->pbackupEnable->isChecked());
101 g.profile[g.id()].splashFile(ui->SplashFileName->text());
103 // The profile name may NEVER be empty
104 if (ui->profileNameLE->text().isEmpty())
105 g.profile[g.id()].name(tr("My Radio"));
106 else
107 g.profile[g.id()].name(ui->profileNameLE->text());
109 // If a new fw type has been choosen, several things need to reset
110 Firmware::setCurrentVariant(getFirmwareVariant());
111 QString id = Firmware::getCurrentVariant()->getId();
112 if (g.profile[g.id()].fwType() != id) {
113 g.profile[g.id()].fwName("");
114 g.profile[g.id()].initFwVariables();
115 g.profile[g.id()].fwType(id);
116 emit firmwareProfileChanged(g.id());
120 void AppPreferencesDialog::on_snapshotPathButton_clicked()
122 QString fileName = QFileDialog::getExistingDirectory(this, tr("Select your snapshot folder"), g.snapshotDir());
123 if (!fileName.isEmpty()) {
124 g.snapshotDir(fileName);
125 g.snapToClpbrd(false);
126 ui->snapshotPath->setText(fileName);
130 void AppPreferencesDialog::initSettings()
132 ui->snapshotClipboardCKB->setChecked(g.snapToClpbrd());
133 ui->burnFirmware->setChecked(g.profile[g.id()].burnFirmware());
134 ui->snapshotPath->setText(g.snapshotDir());
135 ui->snapshotPath->setReadOnly(true);
136 if (ui->snapshotClipboardCKB->isChecked()) {
137 ui->snapshotPath->setDisabled(true);
138 ui->snapshotPathButton->setDisabled(true);
140 #if defined(ALLOW_NIGHTLY_BUILDS)
141 ui->useCompanionNightlyBuilds->setChecked(g.useCompanionNightlyBuilds());
142 ui->useFirmwareNightlyBuilds->setChecked(g.useFirmwareNightlyBuilds());
143 #else
144 ui->useCompanionNightlyBuilds->hide();
145 ui->useFirmwareNightlyBuilds->hide();
146 #endif
147 ui->autoCheckCompanion->setChecked(g.autoCheckApp());
148 ui->autoCheckFirmware->setChecked(g.autoCheckFw());
149 ui->showSplash->setChecked(g.showSplash());
150 ui->historySize->setValue(g.historySize());
151 ui->backLightColor->setCurrentIndex(g.backLight());
152 ui->volumeGain->setValue(g.profile[g.id()].volumeGain() / 10.0);
154 if (IS_TARANIS(getCurrentBoard())) {
155 ui->backLightColor->setEnabled(false);
158 ui->simuSW->setChecked(g.simuSW());
159 ui->opt_removeBlankSlots->setChecked(g.removeModelSlots());
160 ui->opt_newMdl_useNone->setChecked(g.newModelAction() == 0);
161 ui->opt_newMdl_useWizard->setChecked(g.newModelAction() == 1);
162 ui->opt_newMdl_useEditor->setChecked(g.newModelAction() == 2);
163 ui->libraryPath->setText(g.libDir());
164 ui->ge_lineedit->setText(g.gePath());
166 if (!g.backupDir().isEmpty()) {
167 if (QDir(g.backupDir()).exists()) {
168 ui->backupPath->setText(g.backupDir());
169 ui->backupEnable->setEnabled(true);
170 ui->backupEnable->setChecked(g.enableBackup());
172 else {
173 ui->backupEnable->setDisabled(true);
176 else {
177 ui->backupEnable->setDisabled(true);
179 ui->splashincludeCB->setCurrentIndex(g.embedSplashes());
181 ui->opt_appDebugLog->setChecked(g.appDebugLog());
182 ui->opt_fwTraceLog->setChecked(g.fwTraceLog());
183 ui->appLogsDir->setText(g.appLogsDir());
184 toggleAppLogSettings();
186 #if defined(JOYSTICKS)
187 ui->joystickChkB->setChecked(g.jsSupport());
188 if (ui->joystickChkB->isChecked()) {
189 QStringList joystickNames;
190 joystickNames << tr("No joysticks found");
191 joystick = new Joystick(0,false,0,0);
192 ui->joystickcalButton->setDisabled(true);
193 ui->joystickCB->setDisabled(true);
195 if ( joystick ) {
196 if ( joystick->joystickNames.count() > 0 ) {
197 joystickNames = joystick->joystickNames;
198 ui->joystickCB->setEnabled(true);
199 ui->joystickcalButton->setEnabled(true);
201 joystick->close();
203 ui->joystickCB->clear();
204 ui->joystickCB->insertItems(0, joystickNames);
205 ui->joystickCB->setCurrentIndex(g.jsCtrl());
207 else {
208 ui->joystickCB->clear();
209 ui->joystickCB->setDisabled(true);
210 ui->joystickcalButton->setDisabled(true);
212 #endif
213 // Profile Tab Inits
214 ui->channelorderCB->setCurrentIndex(g.profile[g.id()].channelOrder());
215 ui->stickmodeCB->setCurrentIndex(g.profile[g.id()].defaultMode());
216 ui->renameFirmware->setChecked(g.profile[g.id()].renameFwFiles());
217 ui->sdPath->setText(g.profile[g.id()].sdPath());
218 if (!g.profile[g.id()].pBackupDir().isEmpty()) {
219 if (QDir(g.profile[g.id()].pBackupDir()).exists()) {
220 ui->profilebackupPath->setText(g.profile[g.id()].pBackupDir());
221 ui->pbackupEnable->setEnabled(true);
222 ui->pbackupEnable->setChecked(g.profile[g.id()].penableBackup());
223 } else {
224 ui->pbackupEnable->setDisabled(true);
227 else {
228 ui->pbackupEnable->setDisabled(true);
231 ui->profileNameLE->setText(g.profile[g.id()].name());
233 QString hwSettings;
234 if (g.profile[g.id()].stickPotCalib() == "" ) {
235 hwSettings = tr("EMPTY: No radio settings stored in profile");
237 else {
238 QString str = g.profile[g.id()].timeStamp();
239 if (str.isEmpty())
240 hwSettings = tr("AVAILABLE: Radio settings of unknown age");
241 else
242 hwSettings = tr("AVAILABLE: Radio settings stored %1").arg(str);
244 ui->lblGeneralSettings->setText(hwSettings);
246 QString currType = QStringList(g.profile[g.id()].fwType().split('-').mid(0, 2)).join('-');
247 foreach(Firmware * firmware, Firmware::getRegisteredFirmwares()) {
248 ui->downloadVerCB->addItem(firmware->getName(), firmware->getId());
249 if (currType == firmware->getId()) {
250 ui->downloadVerCB->setCurrentIndex(ui->downloadVerCB->count() - 1);
254 baseFirmwareChanged();
257 void AppPreferencesDialog::on_libraryPathButton_clicked()
259 QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your library folder"), g.libDir());
260 if (!fileName.isEmpty()) {
261 g.libDir(fileName);
262 ui->libraryPath->setText(fileName);
266 void AppPreferencesDialog::on_snapshotClipboardCKB_clicked()
268 if (ui->snapshotClipboardCKB->isChecked()) {
269 ui->snapshotPath->setDisabled(true);
270 ui->snapshotPathButton->setDisabled(true);
271 g.snapToClpbrd(true);
273 else {
274 ui->snapshotPath->setEnabled(true);
275 ui->snapshotPath->setReadOnly(true);
276 ui->snapshotPathButton->setEnabled(true);
277 g.snapToClpbrd(false);
281 void AppPreferencesDialog::on_backupPathButton_clicked()
283 QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your Models and Settings backup folder"), g.backupDir());
284 if (!fileName.isEmpty()) {
285 g.backupDir(fileName);
286 ui->backupPath->setText(fileName);
287 ui->backupEnable->setEnabled(true);
291 void AppPreferencesDialog::on_ProfilebackupPathButton_clicked()
293 QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your Models and Settings backup folder"), g.backupDir());
294 if (!fileName.isEmpty()) {
295 ui->profilebackupPath->setText(fileName);
296 ui->pbackupEnable->setEnabled(true);
301 void AppPreferencesDialog::on_btn_appLogsDir_clicked()
303 QString fileName = QFileDialog::getExistingDirectory(this, tr("Select a folder for application logs"), ui->appLogsDir->text());
304 if (!fileName.isEmpty()) {
305 ui->appLogsDir->setText(fileName);
309 void AppPreferencesDialog::on_ge_pathButton_clicked()
311 QString fileName = QFileDialog::getOpenFileName(this, tr("Select Google Earth executable"),ui->ge_lineedit->text());
312 if (!fileName.isEmpty()) {
313 ui->ge_lineedit->setText(fileName);
317 #if defined(JOYSTICKS)
318 void AppPreferencesDialog::on_joystickChkB_clicked() {
319 if (ui->joystickChkB->isChecked()) {
320 QStringList joystickNames;
321 joystickNames << tr("No joysticks found");
322 joystick = new Joystick(0,false,0,0);
323 ui->joystickcalButton->setDisabled(true);
324 ui->joystickCB->setDisabled(true);
326 if ( joystick ) {
327 if ( joystick->joystickNames.count() > 0 ) {
328 joystickNames = joystick->joystickNames;
329 ui->joystickCB->setEnabled(true);
330 ui->joystickcalButton->setEnabled(true);
332 joystick->close();
334 ui->joystickCB->clear();
335 ui->joystickCB->insertItems(0, joystickNames);
337 else {
338 ui->joystickCB->clear();
339 ui->joystickCB->setDisabled(true);
340 ui->joystickcalButton->setDisabled(true);
344 void AppPreferencesDialog::on_joystickcalButton_clicked() {
345 joystickDialog * jd=new joystickDialog(this, ui->joystickCB->currentIndex());
346 jd->exec();
348 #endif
350 // ******** Profile tab functions
352 void AppPreferencesDialog::on_sdPathButton_clicked()
354 QString fileName = QFileDialog::getExistingDirectory(this,tr("Select the folder replicating your SD structure"), g.profile[g.id()].sdPath());
355 if (!fileName.isEmpty()) {
356 ui->sdPath->setText(fileName);
360 bool AppPreferencesDialog::displayImage(const QString & fileName)
362 // Start by clearing the label
363 ui->imageLabel->clear();
365 if (fileName.isEmpty())
366 return false;
368 QImage image(fileName);
369 if (image.isNull())
370 return false;
372 ui->imageLabel->setPixmap(makePixMap(image));
373 ui->imageLabel->setFixedSize(getCurrentFirmware()->getCapability(LcdWidth), getCurrentFirmware()->getCapability(LcdHeight));
374 return true;
377 void AppPreferencesDialog::on_SplashSelect_clicked()
379 QString supportedImageFormats;
380 for (int formatIndex = 0; formatIndex < QImageReader::supportedImageFormats().count(); formatIndex++) {
381 supportedImageFormats += QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex];
384 QString fileName = QFileDialog::getOpenFileName(this,
385 tr("Open Image to load"), g.imagesDir(), tr("Images (%1)").arg(supportedImageFormats));
387 if (!fileName.isEmpty()){
388 g.imagesDir(QFileInfo(fileName).dir().absolutePath());
390 displayImage(fileName);
391 ui->SplashFileName->setText(fileName);
395 void AppPreferencesDialog::on_clearImageButton_clicked()
397 ui->imageLabel->clear();
398 ui->SplashFileName->clear();
402 void AppPreferencesDialog::showVoice(bool show)
404 ui->voiceLabel->setVisible(show);
405 ui->voiceCombo->setVisible(show);
408 void AppPreferencesDialog::baseFirmwareChanged()
410 QString selected_firmware = ui->downloadVerCB->currentData().toString();
412 foreach(Firmware * firmware, Firmware::getRegisteredFirmwares()) {
413 if (firmware->getId() == selected_firmware) {
414 populateFirmwareOptions(firmware);
415 break;
420 Firmware * AppPreferencesDialog::getFirmwareVariant()
422 QString selected_firmware = ui->downloadVerCB->currentData().toString();
424 foreach(Firmware * firmware, Firmware::getRegisteredFirmwares()) {
425 QString id = firmware->getId();
426 if (id == selected_firmware) {
427 foreach(QCheckBox *cb, optionsCheckBoxes) {
428 if (cb->isChecked()) {
429 id += "-" + cb->text();
433 if (voice && voice->isChecked()) {
434 id += "-tts" + ui->voiceCombo->currentText();
437 if (ui->langCombo->count()) {
438 id += "-" + ui->langCombo->currentText();
441 return Firmware::getFirmwareForId(id);
445 // Should never occur...
446 return Firmware::getDefaultVariant();
449 void AppPreferencesDialog::firmwareOptionChanged(bool state)
451 QCheckBox *cb = qobject_cast<QCheckBox*>(sender());
452 if (cb == voice) {
453 showVoice(voice->isChecked());
455 Firmware * firmware=NULL;
456 if (cb && state) {
457 QVariant selected_firmware = ui->downloadVerCB->currentData();
458 foreach(firmware, Firmware::getRegisteredFirmwares()) {
459 if (firmware->getId() == selected_firmware) {
460 foreach(QList<Option> opts, firmware->opts) {
461 foreach(Option opt, opts) {
462 if (cb->text() == opt.name) {
463 foreach(Option other, opts) {
464 if (other.name != opt.name) {
465 foreach(QCheckBox *ocb, optionsCheckBoxes) {
466 if (ocb->text() == other.name) {
467 ocb->setChecked(false);
472 return;
481 void AppPreferencesDialog::toggleAppLogSettings()
483 bool vis = (ui->opt_appDebugLog->isChecked() || ui->opt_fwTraceLog->isChecked());
484 ui->appLogsDir->setVisible(vis);
485 ui->lbl_appLogsDir->setVisible(vis);
486 ui->btn_appLogsDir->setVisible(vis);
489 void AppPreferencesDialog::populateFirmwareOptions(const Firmware * firmware)
491 const Firmware * parent = firmware->getFirmwareBase();
493 updateLock = true;
495 QString id = Firmware::getCurrentVariant()->getId();
496 ui->langCombo->clear();
497 foreach(const char *lang, parent->languages) {
498 ui->langCombo->addItem(lang);
499 if (id.endsWith(lang)) {
500 ui->langCombo->setCurrentIndex(ui->langCombo->count() - 1);
504 voice = NULL; // we will search for a voice checkbox
506 int index = 0;
507 QWidget * prevFocus = ui->voiceCombo;
508 foreach(QList<Option> opts, parent->opts) {
509 foreach(Option opt, opts) {
510 if (index >= optionsCheckBoxes.size()) {
511 QCheckBox * checkbox = new QCheckBox(ui->profileTab);
512 ui->optionsLayout->addWidget(checkbox, optionsCheckBoxes.count()/4, optionsCheckBoxes.count()%4, 1, 1);
513 optionsCheckBoxes.push_back(checkbox);
514 connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(firmwareOptionChanged(bool)));
515 if (prevFocus) {
516 QWidget::setTabOrder(prevFocus, checkbox);
520 QCheckBox *cb = optionsCheckBoxes.at(index++);
521 if (cb) {
522 cb->show();
523 cb->setText(opt.name);
524 cb->setToolTip(opt.tooltip);
525 cb->setCheckState(id.contains(opt.name) ? Qt::Checked : Qt::Unchecked);
526 if (opt.name == QString("voice")) {
527 voice = cb;
529 prevFocus = cb;
534 for (; index<optionsCheckBoxes.size(); index++) {
535 QCheckBox *cb = optionsCheckBoxes.at(index);
536 cb->hide();
537 cb->setCheckState(Qt::Unchecked);
540 ui->voiceCombo->clear();
541 foreach(const char *lang, parent->ttslanguages) {
542 ui->voiceCombo->addItem(lang);
543 if (id.contains(QString("-tts%1").arg(lang))) {
544 ui->voiceCombo->setCurrentIndex(ui->voiceCombo->count() - 1);
548 showVoice(voice && voice->isChecked());
550 // TODO: Remove once splash replacement supported on Horus
551 // NOTE: 480x272 image causes issues on screens <800px high, needs a solution like scrolling once reinstated
552 if (IS_HORUS(parent->getBoard())) {
553 ui->widget_splashImage->hide();
554 ui->SplashFileName->setText("");
556 else {
557 ui->widget_splashImage->show();
558 ui->SplashFileName->setText(g.profile[g.id()].splashFile());
559 displayImage(g.profile[g.id()].splashFile());
562 updateLock = false;
563 QTimer::singleShot(50, this, SLOT(shrink()));
566 void AppPreferencesDialog::shrink()
568 adjustSize();