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"
27 #if defined(JOYSTICKS)
29 #include "joystickdialog.h"
32 AppPreferencesDialog::AppPreferencesDialog(QWidget
* parent
) :
35 mainWinHasDirtyChild(false),
36 ui(new Ui::AppPreferencesDialog
)
39 setWindowIcon(CompanionIcon("apppreferences.png"));
42 connect(ui
->downloadVerCB
, SIGNAL(currentIndexChanged(int)), this, SLOT(baseFirmwareChanged()));
43 connect(ui
->opt_appDebugLog
, &QCheckBox::toggled
, this, &AppPreferencesDialog::toggleAppLogSettings
);
44 connect(ui
->opt_fwTraceLog
, &QCheckBox::toggled
, this, &AppPreferencesDialog::toggleAppLogSettings
);
46 #if !defined(JOYSTICKS)
47 ui
->joystickCB
->hide();
48 ui
->joystickCB
->setDisabled(true);
49 ui
->joystickcalButton
->hide();
50 ui
->joystickChkB
->hide();
57 AppPreferencesDialog::~AppPreferencesDialog()
62 void AppPreferencesDialog::setMainWinHasDirtyChild(bool value
)
64 mainWinHasDirtyChild
= value
;
67 void AppPreferencesDialog::accept()
69 g
.autoCheckApp(ui
->autoCheckCompanion
->isChecked());
70 g
.OpenTxBranch(DownloadBranchType(ui
->OpenTxBranch
->currentIndex()));
71 g
.autoCheckFw(ui
->autoCheckFirmware
->isChecked());
72 g
.showSplash(ui
->showSplash
->isChecked());
73 g
.simuSW(ui
->simuSW
->isChecked());
74 g
.removeModelSlots(ui
->opt_removeBlankSlots
->isChecked());
75 g
.newModelAction(ui
->opt_newMdl_useWizard
->isChecked() ? 1 : ui
->opt_newMdl_useEditor
->isChecked() ? 2 : 0);
76 g
.historySize(ui
->historySize
->value());
77 g
.backLight(ui
->backLightColor
->currentIndex());
78 g
.profile
[g
.id()].volumeGain(round(ui
->volumeGain
->value() * 10.0));
79 g
.libDir(ui
->libraryPath
->text());
80 g
.gePath(ui
->ge_lineedit
->text());
81 g
.embedSplashes(ui
->splashincludeCB
->currentIndex());
82 g
.enableBackup(ui
->backupEnable
->isChecked());
84 g
.appDebugLog(ui
->opt_appDebugLog
->isChecked());
85 g
.fwTraceLog(ui
->opt_fwTraceLog
->isChecked());
86 g
.appLogsDir(ui
->appLogsDir
->text());
88 if (ui
->joystickChkB
->isChecked() && ui
->joystickCB
->isEnabled()) {
89 g
.jsSupport(ui
->joystickChkB
->isChecked());
90 g
.jsCtrl(ui
->joystickCB
->currentIndex());
96 g
.profile
[g
.id()].channelOrder(ui
->channelorderCB
->currentIndex());
97 g
.profile
[g
.id()].defaultMode(ui
->stickmodeCB
->currentIndex());
98 g
.profile
[g
.id()].renameFwFiles(ui
->renameFirmware
->isChecked());
99 g
.profile
[g
.id()].burnFirmware(ui
->burnFirmware
->isChecked());
100 g
.profile
[g
.id()].sdPath(ui
->sdPath
->text());
101 g
.profile
[g
.id()].pBackupDir(ui
->profilebackupPath
->text());
102 g
.profile
[g
.id()].penableBackup(ui
->pbackupEnable
->isChecked());
103 g
.profile
[g
.id()].splashFile(ui
->SplashFileName
->text());
105 // The profile name may NEVER be empty
106 if (ui
->profileNameLE
->text().isEmpty())
107 g
.profile
[g
.id()].name(tr("My Radio"));
109 g
.profile
[g
.id()].name(ui
->profileNameLE
->text());
111 bool fwchange
= false;
112 Firmware
* newFw
= getFirmwareVariant();
113 // If a new fw type has been choosen, several things need to reset
114 if (Firmware::getCurrentVariant()->getId() != newFw
->getId()) {
115 // check if we're going to be converting to a new radio type and there are unsaved files in the main window
116 if (mainWinHasDirtyChild
&& !Boards::isBoardCompatible(Firmware::getCurrentVariant()->getBoard(), newFw
->getBoard())) {
117 QString q
= tr("<p><b>You cannot switch Radio Type or change Build Options while there are unsaved file changes. What do you wish to do?</b></p> <ul>" \
118 "<li><i>Save All</i> - Save any open file(s) before saving Settings.<li>" \
119 "<li><i>Reset</i> - Revert to the previous Radio Type and Build Options before saving Settings.</li>" \
120 "<li><i>Cancel</i> - Return to the Settings editor dialog.</li></ul>");
121 int resp
= QMessageBox::question(this, windowTitle(), q
, (QMessageBox::SaveAll
| QMessageBox::Reset
| QMessageBox::Cancel
), QMessageBox::Cancel
);
122 if (resp
== QMessageBox::SaveAll
) {
123 // signal main window to save files, need to do this before the fw actually changes
124 emit
firmwareProfileAboutToChange();
126 else if (resp
== QMessageBox::Reset
) {
127 // bail out early before saving the radio type & firmware options
132 // we do not accept the dialog close
136 Firmware::setCurrentVariant(newFw
);
137 g
.profile
[g
.id()].fwName("");
138 g
.profile
[g
.id()].initFwVariables();
139 g
.profile
[g
.id()].fwType(newFw
->getId());
146 emit
firmwareProfileChanged(g
.id()); // important to do this after the accepted() signal
149 void AppPreferencesDialog::on_snapshotPathButton_clicked()
151 QString fileName
= QFileDialog::getExistingDirectory(this, tr("Select your snapshot folder"), g
.snapshotDir());
152 if (!fileName
.isEmpty()) {
153 g
.snapshotDir(fileName
);
154 g
.snapToClpbrd(false);
155 ui
->snapshotPath
->setText(fileName
);
159 void AppPreferencesDialog::initSettings()
161 ui
->snapshotClipboardCKB
->setChecked(g
.snapToClpbrd());
162 ui
->burnFirmware
->setChecked(g
.profile
[g
.id()].burnFirmware());
163 ui
->snapshotPath
->setText(g
.snapshotDir());
164 ui
->snapshotPath
->setReadOnly(true);
165 if (ui
->snapshotClipboardCKB
->isChecked()) {
166 ui
->snapshotPath
->setDisabled(true);
167 ui
->snapshotPathButton
->setDisabled(true);
169 #if !defined(ALLOW_NIGHTLY_BUILDS)
170 // TODO should we gray out nightly builds here?
172 ui
->OpenTxBranch
->setCurrentIndex(g
.OpenTxBranch());
173 ui
->autoCheckCompanion
->setChecked(g
.autoCheckApp());
174 ui
->autoCheckFirmware
->setChecked(g
.autoCheckFw());
175 ui
->showSplash
->setChecked(g
.showSplash());
176 ui
->historySize
->setValue(g
.historySize());
177 ui
->backLightColor
->setCurrentIndex(g
.backLight());
178 ui
->volumeGain
->setValue(g
.profile
[g
.id()].volumeGain() / 10.0);
180 if (IS_TARANIS(getCurrentBoard())) {
181 ui
->backLightColor
->setEnabled(false);
184 ui
->simuSW
->setChecked(g
.simuSW());
185 ui
->opt_removeBlankSlots
->setChecked(g
.removeModelSlots());
186 ui
->opt_newMdl_useNone
->setChecked(g
.newModelAction() == 0);
187 ui
->opt_newMdl_useWizard
->setChecked(g
.newModelAction() == 1);
188 ui
->opt_newMdl_useEditor
->setChecked(g
.newModelAction() == 2);
189 ui
->libraryPath
->setText(g
.libDir());
190 ui
->ge_lineedit
->setText(g
.gePath());
192 if (!g
.backupDir().isEmpty()) {
193 if (QDir(g
.backupDir()).exists()) {
194 ui
->backupPath
->setText(g
.backupDir());
195 ui
->backupEnable
->setEnabled(true);
196 ui
->backupEnable
->setChecked(g
.enableBackup());
199 ui
->backupEnable
->setDisabled(true);
203 ui
->backupEnable
->setDisabled(true);
205 ui
->splashincludeCB
->setCurrentIndex(g
.embedSplashes());
207 ui
->opt_appDebugLog
->setChecked(g
.appDebugLog());
208 ui
->opt_fwTraceLog
->setChecked(g
.fwTraceLog());
209 ui
->appLogsDir
->setText(g
.appLogsDir());
210 toggleAppLogSettings();
212 #if defined(JOYSTICKS)
213 ui
->joystickChkB
->setChecked(g
.jsSupport());
214 if (ui
->joystickChkB
->isChecked()) {
215 QStringList joystickNames
;
216 joystickNames
<< tr("No joysticks found");
217 joystick
= new Joystick(0,false,0,0);
218 ui
->joystickcalButton
->setDisabled(true);
219 ui
->joystickCB
->setDisabled(true);
222 if ( joystick
->joystickNames
.count() > 0 ) {
223 joystickNames
= joystick
->joystickNames
;
224 ui
->joystickCB
->setEnabled(true);
225 ui
->joystickcalButton
->setEnabled(true);
229 ui
->joystickCB
->clear();
230 ui
->joystickCB
->insertItems(0, joystickNames
);
231 ui
->joystickCB
->setCurrentIndex(g
.jsCtrl());
234 ui
->joystickCB
->clear();
235 ui
->joystickCB
->setDisabled(true);
236 ui
->joystickcalButton
->setDisabled(true);
240 ui
->channelorderCB
->setCurrentIndex(g
.profile
[g
.id()].channelOrder());
241 ui
->stickmodeCB
->setCurrentIndex(g
.profile
[g
.id()].defaultMode());
242 ui
->renameFirmware
->setChecked(g
.profile
[g
.id()].renameFwFiles());
243 ui
->sdPath
->setText(g
.profile
[g
.id()].sdPath());
244 if (!g
.profile
[g
.id()].pBackupDir().isEmpty()) {
245 if (QDir(g
.profile
[g
.id()].pBackupDir()).exists()) {
246 ui
->profilebackupPath
->setText(g
.profile
[g
.id()].pBackupDir());
247 ui
->pbackupEnable
->setEnabled(true);
248 ui
->pbackupEnable
->setChecked(g
.profile
[g
.id()].penableBackup());
250 ui
->pbackupEnable
->setDisabled(true);
254 ui
->pbackupEnable
->setDisabled(true);
257 ui
->profileNameLE
->setText(g
.profile
[g
.id()].name());
260 if (g
.profile
[g
.id()].stickPotCalib() == "" ) {
261 hwSettings
= tr("EMPTY: No radio settings stored in profile");
264 QString str
= g
.profile
[g
.id()].timeStamp();
266 hwSettings
= tr("AVAILABLE: Radio settings of unknown age");
268 hwSettings
= tr("AVAILABLE: Radio settings stored %1").arg(str
);
270 ui
->lblGeneralSettings
->setText(hwSettings
);
272 QString currType
= QStringList(g
.profile
[g
.id()].fwType().split('-').mid(0, 2)).join('-');
273 foreach(Firmware
* firmware
, Firmware::getRegisteredFirmwares()) {
274 ui
->downloadVerCB
->addItem(firmware
->getName(), firmware
->getId());
275 if (currType
== firmware
->getId()) {
276 ui
->downloadVerCB
->setCurrentIndex(ui
->downloadVerCB
->count() - 1);
280 baseFirmwareChanged();
283 void AppPreferencesDialog::on_libraryPathButton_clicked()
285 QString fileName
= QFileDialog::getExistingDirectory(this,tr("Select your library folder"), g
.libDir());
286 if (!fileName
.isEmpty()) {
288 ui
->libraryPath
->setText(fileName
);
292 void AppPreferencesDialog::on_snapshotClipboardCKB_clicked()
294 if (ui
->snapshotClipboardCKB
->isChecked()) {
295 ui
->snapshotPath
->setDisabled(true);
296 ui
->snapshotPathButton
->setDisabled(true);
297 g
.snapToClpbrd(true);
300 ui
->snapshotPath
->setEnabled(true);
301 ui
->snapshotPath
->setReadOnly(true);
302 ui
->snapshotPathButton
->setEnabled(true);
303 g
.snapToClpbrd(false);
307 void AppPreferencesDialog::on_backupPathButton_clicked()
309 QString fileName
= QFileDialog::getExistingDirectory(this,tr("Select your Models and Settings backup folder"), g
.backupDir());
310 if (!fileName
.isEmpty()) {
311 g
.backupDir(fileName
);
312 ui
->backupPath
->setText(fileName
);
313 ui
->backupEnable
->setEnabled(true);
317 void AppPreferencesDialog::on_ProfilebackupPathButton_clicked()
319 QString fileName
= QFileDialog::getExistingDirectory(this,tr("Select your Models and Settings backup folder"), g
.backupDir());
320 if (!fileName
.isEmpty()) {
321 ui
->profilebackupPath
->setText(fileName
);
322 ui
->pbackupEnable
->setEnabled(true);
327 void AppPreferencesDialog::on_btn_appLogsDir_clicked()
329 QString fileName
= QFileDialog::getExistingDirectory(this, tr("Select a folder for application logs"), ui
->appLogsDir
->text());
330 if (!fileName
.isEmpty()) {
331 ui
->appLogsDir
->setText(fileName
);
335 void AppPreferencesDialog::on_ge_pathButton_clicked()
337 QString fileName
= QFileDialog::getOpenFileName(this, tr("Select Google Earth executable"),ui
->ge_lineedit
->text());
338 if (!fileName
.isEmpty()) {
339 ui
->ge_lineedit
->setText(fileName
);
343 #if defined(JOYSTICKS)
344 void AppPreferencesDialog::on_joystickChkB_clicked() {
345 if (ui
->joystickChkB
->isChecked()) {
346 QStringList joystickNames
;
347 joystickNames
<< tr("No joysticks found");
348 joystick
= new Joystick(0,false,0,0);
349 ui
->joystickcalButton
->setDisabled(true);
350 ui
->joystickCB
->setDisabled(true);
353 if ( joystick
->joystickNames
.count() > 0 ) {
354 joystickNames
= joystick
->joystickNames
;
355 ui
->joystickCB
->setEnabled(true);
356 ui
->joystickcalButton
->setEnabled(true);
360 ui
->joystickCB
->clear();
361 ui
->joystickCB
->insertItems(0, joystickNames
);
364 ui
->joystickCB
->clear();
365 ui
->joystickCB
->setDisabled(true);
366 ui
->joystickcalButton
->setDisabled(true);
370 void AppPreferencesDialog::on_joystickcalButton_clicked() {
371 joystickDialog
* jd
=new joystickDialog(this, ui
->joystickCB
->currentIndex());
376 // ******** Profile tab functions
378 void AppPreferencesDialog::on_sdPathButton_clicked()
380 QString fileName
= QFileDialog::getExistingDirectory(this,tr("Select the folder replicating your SD structure"), g
.profile
[g
.id()].sdPath());
381 if (!fileName
.isEmpty()) {
382 ui
->sdPath
->setText(fileName
);
386 bool AppPreferencesDialog::displayImage(const QString
& fileName
)
388 // Start by clearing the label
389 ui
->imageLabel
->clear();
391 if (fileName
.isEmpty())
394 QImage
image(fileName
);
398 ui
->imageLabel
->setPixmap(makePixMap(image
));
399 ui
->imageLabel
->setFixedSize(getCurrentFirmware()->getCapability(LcdWidth
), getCurrentFirmware()->getCapability(LcdHeight
));
403 void AppPreferencesDialog::on_SplashSelect_clicked()
405 QString supportedImageFormats
;
406 for (int formatIndex
= 0; formatIndex
< QImageReader::supportedImageFormats().count(); formatIndex
++) {
407 supportedImageFormats
+= QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex
];
410 QString fileName
= QFileDialog::getOpenFileName(this,
411 tr("Open Image to load"), g
.imagesDir(), tr("Images (%1)").arg(supportedImageFormats
));
413 if (!fileName
.isEmpty()){
414 g
.imagesDir(QFileInfo(fileName
).dir().absolutePath());
416 displayImage(fileName
);
417 ui
->SplashFileName
->setText(fileName
);
421 void AppPreferencesDialog::on_clearImageButton_clicked()
423 ui
->imageLabel
->clear();
424 ui
->SplashFileName
->clear();
428 void AppPreferencesDialog::showVoice(bool show
)
430 ui
->voiceLabel
->setVisible(show
);
431 ui
->voiceCombo
->setVisible(show
);
434 void AppPreferencesDialog::baseFirmwareChanged()
436 QString selected_firmware
= ui
->downloadVerCB
->currentData().toString();
438 foreach(Firmware
* firmware
, Firmware::getRegisteredFirmwares()) {
439 if (firmware
->getId() == selected_firmware
) {
440 populateFirmwareOptions(firmware
);
446 Firmware
* AppPreferencesDialog::getFirmwareVariant()
448 QString selected_firmware
= ui
->downloadVerCB
->currentData().toString();
450 foreach(Firmware
* firmware
, Firmware::getRegisteredFirmwares()) {
451 QString id
= firmware
->getId();
452 if (id
== selected_firmware
) {
453 foreach(QCheckBox
*cb
, optionsCheckBoxes
) {
454 if (cb
->isChecked()) {
455 id
+= "-" + cb
->text();
459 if (voice
&& voice
->isChecked()) {
460 id
+= "-tts" + ui
->voiceCombo
->currentText();
463 if (ui
->langCombo
->count()) {
464 id
+= "-" + ui
->langCombo
->currentText();
467 return Firmware::getFirmwareForId(id
);
471 // Should never occur...
472 return Firmware::getDefaultVariant();
475 void AppPreferencesDialog::firmwareOptionChanged(bool state
)
477 QCheckBox
*cb
= qobject_cast
<QCheckBox
*>(sender());
479 showVoice(voice
->isChecked());
481 Firmware
* firmware
=NULL
;
483 QVariant selected_firmware
= ui
->downloadVerCB
->currentData();
484 foreach(firmware
, Firmware::getRegisteredFirmwares()) {
485 if (firmware
->getId() == selected_firmware
) {
486 foreach(QList
<Option
> opts
, firmware
->opts
) {
487 foreach(Option opt
, opts
) {
488 if (cb
->text() == opt
.name
) {
489 foreach(Option other
, opts
) {
490 if (other
.name
!= opt
.name
) {
491 foreach(QCheckBox
*ocb
, optionsCheckBoxes
) {
492 if (ocb
->text() == other
.name
) {
493 ocb
->setChecked(false);
507 void AppPreferencesDialog::toggleAppLogSettings()
509 bool vis
= (ui
->opt_appDebugLog
->isChecked() || ui
->opt_fwTraceLog
->isChecked());
510 ui
->appLogsDir
->setVisible(vis
);
511 ui
->lbl_appLogsDir
->setVisible(vis
);
512 ui
->btn_appLogsDir
->setVisible(vis
);
515 void AppPreferencesDialog::populateFirmwareOptions(const Firmware
* firmware
)
517 const Firmware
* parent
= firmware
->getFirmwareBase();
521 QString id
= Firmware::getCurrentVariant()->getId();
522 ui
->langCombo
->clear();
523 foreach(const char *lang
, parent
->languages
) {
524 ui
->langCombo
->addItem(lang
);
525 if (id
.endsWith(lang
)) {
526 ui
->langCombo
->setCurrentIndex(ui
->langCombo
->count() - 1);
530 voice
= NULL
; // we will search for a voice checkbox
533 QWidget
* prevFocus
= ui
->voiceCombo
;
534 foreach(QList
<Option
> opts
, parent
->opts
) {
535 foreach(Option opt
, opts
) {
536 if (index
>= optionsCheckBoxes
.size()) {
537 QCheckBox
* checkbox
= new QCheckBox(ui
->profileTab
);
538 ui
->optionsLayout
->addWidget(checkbox
, optionsCheckBoxes
.count()/4, optionsCheckBoxes
.count()%4, 1, 1);
539 optionsCheckBoxes
.push_back(checkbox
);
540 connect(checkbox
, SIGNAL(toggled(bool)), this, SLOT(firmwareOptionChanged(bool)));
542 QWidget::setTabOrder(prevFocus
, checkbox
);
546 QCheckBox
*cb
= optionsCheckBoxes
.at(index
++);
549 cb
->setText(opt
.name
);
550 cb
->setToolTip(opt
.tooltip
);
551 cb
->setCheckState(id
.contains(opt
.name
) ? Qt::Checked
: Qt::Unchecked
);
552 if (opt
.name
== QString("voice")) {
560 for (; index
<optionsCheckBoxes
.size(); index
++) {
561 QCheckBox
*cb
= optionsCheckBoxes
.at(index
);
563 cb
->setCheckState(Qt::Unchecked
);
566 ui
->voiceCombo
->clear();
567 foreach(const char *lang
, parent
->ttslanguages
) {
568 ui
->voiceCombo
->addItem(lang
);
569 if (id
.contains(QString("-tts%1").arg(lang
))) {
570 ui
->voiceCombo
->setCurrentIndex(ui
->voiceCombo
->count() - 1);
574 showVoice(voice
&& voice
->isChecked());
576 // TODO: Remove once splash replacement supported on Horus
577 // NOTE: 480x272 image causes issues on screens <800px high, needs a solution like scrolling once reinstated
578 if (IS_HORUS(parent
->getBoard())) {
579 ui
->widget_splashImage
->hide();
580 ui
->SplashFileName
->setText("");
583 ui
->widget_splashImage
->show();
584 ui
->SplashFileName
->setText(g
.profile
[g
.id()].splashFile());
585 displayImage(g
.profile
[g
.id()].splashFile());
589 QTimer::singleShot(50, this, SLOT(shrink()));
592 void AppPreferencesDialog::shrink()