WSJT-X/TestConfiguration.cpp

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 ();
}