mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-16 09:01:59 -05:00
471 lines
15 KiB
C++
471 lines
15 KiB
C++
|
#include "TestConfiguration.hpp"
|
||
|
|
||
|
#include <cstdlib>
|
||
|
|
||
|
#include <QApplication>
|
||
|
#include <QSettings>
|
||
|
#include <QMainWindow>
|
||
|
#include <QLabel>
|
||
|
#include <QDir>
|
||
|
#include <QMessageBox>
|
||
|
#include <QLineEdit>
|
||
|
#include <QDebug>
|
||
|
#include <QSortFilterProxyModel>
|
||
|
|
||
|
#include "Bands.hpp"
|
||
|
#include "FrequencyList.hpp"
|
||
|
#include "Configuration.hpp"
|
||
|
#include "LiveFrequencyValidator.hpp"
|
||
|
|
||
|
#include "pimpl_impl.hpp"
|
||
|
|
||
|
#include "ui_TestConfiguration.h"
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
char const * const title = "Configuration Test v" WSJTX_STRINGIZE (CONFIG_TEST_VERSION_MAJOR) "." WSJTX_STRINGIZE (CONFIG_TEST_VERSION_MINOR) "." WSJTX_STRINGIZE (CONFIG_TEST_VERSION_PATCH) ", " WSJTX_STRINGIZE (SVNVERSION);
|
||
|
|
||
|
// these undocumented flag values when stored in (Qt::UserRole - 1)
|
||
|
// of a ComboBox item model index allow the item to be enabled or
|
||
|
// disabled
|
||
|
int const combo_box_item_enabled (32 | 1);
|
||
|
int const combo_box_item_disabled (0);
|
||
|
|
||
|
auto LCD_error = "-- Error --";
|
||
|
}
|
||
|
|
||
|
class status_bar_frequency final
|
||
|
: public QLabel
|
||
|
{
|
||
|
public:
|
||
|
status_bar_frequency (QString const& prefix, QWidget * parent = 0)
|
||
|
: QLabel {parent}
|
||
|
, prefix_ {prefix}
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void setText (QString const& text)
|
||
|
{
|
||
|
QLabel::setText (prefix_ + " Frequency: " + text);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
QString prefix_;
|
||
|
};
|
||
|
|
||
|
class TestConfiguration::impl final
|
||
|
: public QMainWindow
|
||
|
{
|
||
|
Q_OBJECT;
|
||
|
|
||
|
public:
|
||
|
using Frequency = Radio::Frequency;
|
||
|
|
||
|
explicit impl (QString const& instance_key, QSettings *, QWidget * parent = nullptr);
|
||
|
|
||
|
void closeEvent (QCloseEvent *) override;
|
||
|
|
||
|
Q_SIGNAL void new_frequency (Frequency) const;
|
||
|
Q_SIGNAL void new_tx_frequency (Frequency = 0, bool rationalise_mode = true) const;
|
||
|
|
||
|
private:
|
||
|
Q_SLOT void on_configuration_action_triggered ();
|
||
|
Q_SLOT void on_band_combo_box_activated (int);
|
||
|
Q_SLOT void on_mode_combo_box_activated (int);
|
||
|
Q_SLOT void on_PTT_push_button_clicked (bool);
|
||
|
Q_SLOT void on_split_push_button_clicked (bool);
|
||
|
Q_SLOT void on_TX_offset_spin_box_valueChanged (int);
|
||
|
Q_SLOT void on_sync_push_button_clicked (bool);
|
||
|
|
||
|
Q_SLOT void handle_transceiver_update (Transceiver::TransceiverState);
|
||
|
Q_SLOT void handle_transceiver_failure (QString);
|
||
|
|
||
|
void information_message_box (QString const& reason, QString const& detail);
|
||
|
void read_settings ();
|
||
|
void write_settings ();
|
||
|
void load_models ();
|
||
|
void sync_rig ();
|
||
|
void band_changed (Frequency);
|
||
|
void frequency_changed (Frequency);
|
||
|
|
||
|
Ui::test_configuration_main_window * ui_;
|
||
|
QSettings * settings_;
|
||
|
QString callsign_;
|
||
|
Configuration configuration_dialog_;
|
||
|
bool updating_models_; // hold off UI reaction while adjusting models
|
||
|
bool band_edited_;
|
||
|
|
||
|
Transceiver::TransceiverState rig_state_;
|
||
|
|
||
|
Frequency desired_frequency_;
|
||
|
|
||
|
status_bar_frequency RX_frequency_;
|
||
|
status_bar_frequency TX_frequency_;
|
||
|
};
|
||
|
|
||
|
#include "TestConfiguration.moc"
|
||
|
|
||
|
TestConfiguration::TestConfiguration (QString const& instance_key, QSettings * settings, QWidget * parent)
|
||
|
: m_ {instance_key, settings, parent}
|
||
|
{
|
||
|
}
|
||
|
|
||
|
TestConfiguration::~TestConfiguration ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
TestConfiguration::impl::impl (QString const& instance_key, QSettings * settings, QWidget * parent)
|
||
|
: QMainWindow {parent}
|
||
|
, ui_ {new Ui::test_configuration_main_window}
|
||
|
, settings_ {settings}
|
||
|
, configuration_dialog_ {instance_key, settings, this}
|
||
|
, updating_models_ {false}
|
||
|
, band_edited_ {false}
|
||
|
, desired_frequency_ {0u}
|
||
|
, RX_frequency_ {"RX"}
|
||
|
, TX_frequency_ {"TX"}
|
||
|
{
|
||
|
ui_->setupUi (this);
|
||
|
|
||
|
setWindowTitle (QApplication::applicationName () + " - " + title);
|
||
|
|
||
|
// mode "Unknown" is display only
|
||
|
ui_->mode_combo_box->setItemData (ui_->mode_combo_box->findText ("Unknown"), combo_box_item_disabled, Qt::UserRole - 1);
|
||
|
|
||
|
// setup status bar widgets
|
||
|
statusBar ()->insertPermanentWidget (0, &TX_frequency_);
|
||
|
statusBar ()->insertPermanentWidget (0, &RX_frequency_);
|
||
|
|
||
|
// assign push button ids
|
||
|
ui_->TX_button_group->setId (ui_->vfo_0_TX_push_button, 0);
|
||
|
ui_->TX_button_group->setId (ui_->vfo_1_TX_push_button, 1);
|
||
|
|
||
|
// enable live band combo box entry validation and action
|
||
|
auto band_validator = new LiveFrequencyValidator {ui_->band_combo_box
|
||
|
, configuration_dialog_.bands ()
|
||
|
, configuration_dialog_.frequencies ()
|
||
|
, this};
|
||
|
ui_->band_combo_box->setValidator (band_validator);
|
||
|
connect (band_validator, &LiveFrequencyValidator::valid, this, &TestConfiguration::impl::band_changed);
|
||
|
connect (ui_->band_combo_box->lineEdit (), &QLineEdit::textEdited, [this] (QString const&) {band_edited_ = true;});
|
||
|
|
||
|
// hook up band data model
|
||
|
ui_->band_combo_box->setModel (configuration_dialog_.frequencies ());
|
||
|
|
||
|
// combo box drop downs are limited to the drop down selector width,
|
||
|
// this almost random increase improves the situation
|
||
|
ui_->band_combo_box->view ()->setMinimumWidth (ui_->band_combo_box->view ()->sizeHintForColumn (0) + 10);
|
||
|
|
||
|
// hook up configuration signals
|
||
|
connect (&configuration_dialog_, &Configuration::transceiver_update, this, &TestConfiguration::impl::handle_transceiver_update);
|
||
|
connect (&configuration_dialog_, &Configuration::transceiver_failure, this, &TestConfiguration::impl::handle_transceiver_failure);
|
||
|
|
||
|
// hook up configuration slots
|
||
|
connect (this, &TestConfiguration::impl::new_frequency, &configuration_dialog_, &Configuration::transceiver_frequency);
|
||
|
connect (this, &TestConfiguration::impl::new_tx_frequency, &configuration_dialog_, &Configuration::transceiver_tx_frequency);
|
||
|
|
||
|
load_models ();
|
||
|
|
||
|
read_settings ();
|
||
|
|
||
|
show ();
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::closeEvent (QCloseEvent * e)
|
||
|
{
|
||
|
write_settings ();
|
||
|
|
||
|
QMainWindow::closeEvent (e);
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_configuration_action_triggered ()
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_configuration_action_triggered";
|
||
|
if (QDialog::Accepted == configuration_dialog_.exec ())
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_configuration_action_triggered: Configuration changed";
|
||
|
qDebug () << "TestConfiguration::on_configuration_action_triggered: rig is" << configuration_dialog_.rig_name ();
|
||
|
|
||
|
if (configuration_dialog_.restart_audio_input ())
|
||
|
{
|
||
|
qDebug () << "Audio Device Changes - Configuration changes require an audio input device to be restarted";
|
||
|
}
|
||
|
if (configuration_dialog_.restart_audio_output ())
|
||
|
{
|
||
|
qDebug () << "Audio Device Changes - Configuration changes require an audio output device to be restarted";
|
||
|
}
|
||
|
|
||
|
load_models ();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_configuration_action_triggered: Confiugration changes cancelled";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_band_combo_box_activated (int index)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_band_combo_box_activated: " << ui_->band_combo_box->currentText ();
|
||
|
|
||
|
auto model = configuration_dialog_.frequencies ();
|
||
|
auto value = model->data (model->index (index, 2), Qt::DisplayRole).toString ();
|
||
|
|
||
|
if (configuration_dialog_.bands ()->data (QModelIndex {}).toString () == value)
|
||
|
{
|
||
|
ui_->band_combo_box->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui_->band_combo_box->lineEdit ()->setStyleSheet ({});
|
||
|
}
|
||
|
|
||
|
ui_->band_combo_box->setCurrentText (value);
|
||
|
|
||
|
auto f = model->data (model->index (index, 0), Qt::UserRole + 1).value<Frequency> ();
|
||
|
|
||
|
band_edited_ = true;
|
||
|
band_changed (f);
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::band_changed (Frequency f)
|
||
|
{
|
||
|
if (band_edited_)
|
||
|
{
|
||
|
band_edited_ = false;
|
||
|
frequency_changed (f);
|
||
|
sync_rig ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::frequency_changed (Frequency f)
|
||
|
{
|
||
|
desired_frequency_ = f;
|
||
|
|
||
|
// lookup band
|
||
|
auto bands_model = configuration_dialog_.bands ();
|
||
|
ui_->band_combo_box->setCurrentText (bands_model->data (bands_model->find (f)).toString ());
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_sync_push_button_clicked (bool /* checked */)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_sync_push_button_clicked";
|
||
|
|
||
|
auto model = configuration_dialog_.frequencies ();
|
||
|
auto model_index = model->index (ui_->band_combo_box->currentIndex (), 0);
|
||
|
desired_frequency_ = model->data (model_index, Qt::UserRole + 1).value<Frequency> ();
|
||
|
|
||
|
sync_rig ();
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_mode_combo_box_activated (int index)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_vfo_A_mode_combo_box_activated: " << static_cast<Transceiver::MODE> (index);
|
||
|
|
||
|
// reset combo box back to current mode and let status update do the actual change
|
||
|
ui_->mode_combo_box->setCurrentIndex (rig_state_.mode ());
|
||
|
|
||
|
Q_EMIT configuration_dialog_.transceiver_mode (static_cast<Transceiver::MODE> (index));
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_TX_offset_spin_box_valueChanged (int value)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_TX_offset_spin_box_editingFinished: " << value;
|
||
|
|
||
|
Q_EMIT new_tx_frequency (rig_state_.frequency () + value);
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_PTT_push_button_clicked (bool checked)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_PTT_push_button_clicked: " << (checked ? "true" : "false");
|
||
|
|
||
|
// reset button and let status update do the actual checking
|
||
|
ui_->PTT_push_button->setChecked (rig_state_.ptt ());
|
||
|
|
||
|
Q_EMIT configuration_dialog_.transceiver_ptt (checked);
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::on_split_push_button_clicked (bool checked)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::on_split_push_button_clicked: " << (checked ? "true" : "false");
|
||
|
|
||
|
// reset button and let status update do the actual checking
|
||
|
ui_->split_push_button->setChecked (rig_state_.split ());
|
||
|
|
||
|
if (checked)
|
||
|
{
|
||
|
Q_EMIT new_tx_frequency (rig_state_.frequency () + ui_->TX_offset_spin_box->value ());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Q_EMIT new_tx_frequency ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::sync_rig ()
|
||
|
{
|
||
|
if (!updating_models_)
|
||
|
{
|
||
|
if (configuration_dialog_.transceiver_online (true))
|
||
|
{
|
||
|
if (configuration_dialog_.split_mode ())
|
||
|
{
|
||
|
Q_EMIT new_frequency (desired_frequency_);
|
||
|
Q_EMIT new_tx_frequency (desired_frequency_ + ui_->TX_offset_spin_box->value ());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Q_EMIT new_frequency (desired_frequency_);
|
||
|
Q_EMIT new_tx_frequency ();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::handle_transceiver_update (Transceiver::TransceiverState s)
|
||
|
{
|
||
|
rig_state_ = s;
|
||
|
|
||
|
auto model = configuration_dialog_.frequencies ();
|
||
|
bool valid {false};
|
||
|
for (int row = 0; row < model->rowCount (); ++row)
|
||
|
{
|
||
|
auto working_frequency = model->data (model->index (row, 0), Qt::UserRole + 1).value<Frequency> ();
|
||
|
if (std::abs (static_cast<Radio::FrequencyDelta> (working_frequency - s.frequency ())) < 10000)
|
||
|
{
|
||
|
valid = true;
|
||
|
}
|
||
|
}
|
||
|
if (!valid)
|
||
|
{
|
||
|
ui_->vfo_0_lcd_number->setStyleSheet ("QLCDNumber {background-color: red;}");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui_->vfo_0_lcd_number->setStyleSheet (QString {});
|
||
|
}
|
||
|
|
||
|
ui_->vfo_0_lcd_number->display (Radio::pretty_frequency_MHz_string (s.frequency ()));
|
||
|
|
||
|
if (s.split ())
|
||
|
{
|
||
|
ui_->vfo_1_lcd_number->display (Radio::pretty_frequency_MHz_string (s.tx_frequency ()));
|
||
|
|
||
|
valid = false;
|
||
|
for (int row = 0; row < model->rowCount (); ++row)
|
||
|
{
|
||
|
auto working_frequency = model->data (model->index (row, 0), Qt::UserRole + 1).value<Frequency> ();
|
||
|
if (std::abs (static_cast<Radio::FrequencyDelta> (working_frequency - s.tx_frequency ())) < 10000)
|
||
|
{
|
||
|
valid = true;
|
||
|
}
|
||
|
}
|
||
|
if (!valid)
|
||
|
{
|
||
|
ui_->vfo_1_lcd_number->setStyleSheet ("QLCDNumber {background-color: red;}");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui_->vfo_1_lcd_number->setStyleSheet (QString {});
|
||
|
}
|
||
|
ui_->vfo_1_lcd_number->show ();
|
||
|
ui_->vfo_1_TX_push_button->show ();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui_->vfo_1_lcd_number->hide ();
|
||
|
ui_->vfo_1_TX_push_button->hide ();
|
||
|
}
|
||
|
|
||
|
frequency_changed (s.frequency ());
|
||
|
|
||
|
ui_->radio_widget->setEnabled (s.online ());
|
||
|
|
||
|
ui_->mode_combo_box->setCurrentIndex (s.mode ());
|
||
|
|
||
|
RX_frequency_.setText (Radio::pretty_frequency_MHz_string (s.frequency ()));
|
||
|
TX_frequency_.setText (Radio::pretty_frequency_MHz_string (s.split () ? s.tx_frequency () : s.frequency ()));
|
||
|
|
||
|
ui_->TX_button_group->button (s.split ())->setChecked (true);
|
||
|
|
||
|
ui_->PTT_push_button->setChecked (s.ptt ());
|
||
|
|
||
|
ui_->split_push_button->setChecked (s.split ());
|
||
|
|
||
|
ui_->radio_widget->setEnabled (s.online ());
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::handle_transceiver_failure (QString reason)
|
||
|
{
|
||
|
ui_->radio_widget->setEnabled (false);
|
||
|
|
||
|
ui_->vfo_0_lcd_number->display (LCD_error);
|
||
|
ui_->vfo_1_lcd_number->display (LCD_error);
|
||
|
information_message_box ("Rig failure", reason);
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::read_settings ()
|
||
|
{
|
||
|
settings_->beginGroup ("TestConfiguration");
|
||
|
resize (settings_->value ("window/size", size ()).toSize ());
|
||
|
move (settings_->value ("window/pos", pos ()).toPoint ());
|
||
|
restoreState (settings_->value ("window/state", saveState ()).toByteArray ());
|
||
|
ui_->band_combo_box->setCurrentText (settings_->value ("Band").toString ());
|
||
|
settings_->endGroup ();
|
||
|
|
||
|
settings_->beginGroup ("Configuration");
|
||
|
callsign_ = settings_->value ("MyCall").toString ();
|
||
|
settings_->endGroup ();
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::write_settings ()
|
||
|
{
|
||
|
settings_->beginGroup ("TestConfiguration");
|
||
|
settings_->setValue ("window/size", size ());
|
||
|
settings_->setValue ("window/pos", pos ());
|
||
|
settings_->setValue ("window/state", saveState ());
|
||
|
settings_->setValue ("Band", ui_->band_combo_box->currentText ());
|
||
|
settings_->endGroup ();
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::load_models ()
|
||
|
{
|
||
|
updating_models_ = true;
|
||
|
|
||
|
ui_->frequency_group_box->setTitle (configuration_dialog_.rig_name ());
|
||
|
// if (auto rig = configuration_dialog_.rig (false)) // don't open radio
|
||
|
if (configuration_dialog_.transceiver_online (false)) // don't open radio
|
||
|
{
|
||
|
Q_EMIT configuration_dialog_.sync_transceiver (true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui_->radio_widget->setEnabled (false);
|
||
|
ui_->vfo_0_lcd_number->display (Radio::pretty_frequency_MHz_string (static_cast<Frequency> (0)));
|
||
|
ui_->vfo_1_lcd_number->display (Radio::pretty_frequency_MHz_string (static_cast<Frequency> (0)));
|
||
|
}
|
||
|
|
||
|
if (!configuration_dialog_.split_mode ())
|
||
|
{
|
||
|
ui_->vfo_1_lcd_number->hide ();
|
||
|
ui_->vfo_1_TX_push_button->hide ();
|
||
|
}
|
||
|
|
||
|
updating_models_ = false;
|
||
|
}
|
||
|
|
||
|
void TestConfiguration::impl::information_message_box (QString const& reason, QString const& detail)
|
||
|
{
|
||
|
qDebug () << "TestConfiguration::information_message_box: reason =" << reason << "detail =" << detail;
|
||
|
QMessageBox mb;
|
||
|
mb.setWindowFlags (mb.windowFlags () | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||
|
mb.setText (reason);
|
||
|
if (!detail.isEmpty ())
|
||
|
{
|
||
|
mb.setDetailedText (detail);
|
||
|
}
|
||
|
mb.setStandardButtons (QMessageBox::Ok);
|
||
|
mb.setDefaultButton (QMessageBox::Ok);
|
||
|
mb.setIcon (QMessageBox::Information);
|
||
|
mb.exec ();
|
||
|
}
|