diff --git a/Configuration.cpp b/Configuration.cpp index 657e6d9b0..8c761b6f6 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -534,7 +534,7 @@ private: bool miles_; bool quick_call_; bool disable_TX_on_73_; - bool watchdog_; + int watchdog_; bool TX_messages_; bool enable_VHF_features_; bool decode_at_52s_; @@ -623,7 +623,7 @@ bool Configuration::clear_DX () const {return m_->clear_DX_;} bool Configuration::miles () const {return m_->miles_;} bool Configuration::quick_call () const {return m_->quick_call_;} bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;} -bool Configuration::watchdog () const {return m_->watchdog_;} +int Configuration::watchdog () const {return m_->watchdog_;} bool Configuration::TX_messages () const {return m_->TX_messages_;} bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features_;} bool Configuration::decode_at_52s () const {return m_->decode_at_52s_;} @@ -1054,7 +1054,7 @@ void Configuration::impl::initialize_models () ui_->miles_check_box->setChecked (miles_); ui_->quick_call_check_box->setChecked (quick_call_); ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_); - ui_->watchdog_check_box->setChecked (watchdog_); + ui_->tx_watchdog_spin_box->setValue (watchdog_); ui_->TX_messages_check_box->setChecked (TX_messages_); ui_->enable_VHF_features_check_box->setChecked(enable_VHF_features_); ui_->decode_at_52s_check_box->setChecked(decode_at_52s_); @@ -1282,7 +1282,7 @@ void Configuration::impl::read_settings () miles_ = settings_->value ("Miles", false).toBool (); quick_call_ = settings_->value ("QuickCall", false).toBool (); disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool (); - watchdog_ = settings_->value ("Runaway", false).toBool (); + watchdog_ = settings_->value ("TxWatchdog", 6).toInt (); TX_messages_ = settings_->value ("Tx2QSO", true).toBool (); enable_VHF_features_ = settings_->value("VHFUHF",false).toBool (); decode_at_52s_ = settings_->value("Decode52",false).toBool (); @@ -1376,7 +1376,7 @@ void Configuration::impl::write_settings () settings_->setValue ("Miles", miles_); settings_->setValue ("QuickCall", quick_call_); settings_->setValue ("73TxDisable", disable_TX_on_73_); - settings_->setValue ("Runaway", watchdog_); + settings_->setValue ("TxWatchdog", watchdog_); settings_->setValue ("Tx2QSO", TX_messages_); settings_->setValue ("CATForceDTR", rig_params_.force_dtr); settings_->setValue ("DTR", rig_params_.dtr_high); @@ -1777,7 +1777,7 @@ void Configuration::impl::accept () miles_ = ui_->miles_check_box->isChecked (); quick_call_ = ui_->quick_call_check_box->isChecked (); disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked (); - watchdog_ = ui_->watchdog_check_box->isChecked (); + watchdog_ = ui_->tx_watchdog_spin_box->value (); TX_messages_ = ui_->TX_messages_check_box->isChecked (); data_mode_ = static_cast (ui_->TX_mode_button_group->checkedId ()); save_directory_ = ui_->save_path_display_label->text (); diff --git a/Configuration.hpp b/Configuration.hpp index 4c0f99c44..b2cbae192 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -113,7 +113,7 @@ public: bool miles () const; bool quick_call () const; bool disable_TX_on_73 () const; - bool watchdog () const; + int watchdog () const; bool TX_messages () const; bool split_mode () const; bool enable_VHF_features () const; diff --git a/Configuration.ui b/Configuration.ui index 3d6379b7d..cfb7b886f 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -132,6 +132,16 @@ Display + + + + Include a separator line between periods in the band activity window. + + + &Blank line between decoding periods + + + @@ -145,13 +155,36 @@ - - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - Include a separator line between periods in the band activity window. + Show distance to DX station in miles rather than kilometers. - &Blank line between decoding periods + Display dista&nce in miles + + + + + + + Show outgoing transmitted messages in the Rx frequency window. + + + &Tx messages to Rx frequency window @@ -192,39 +225,6 @@ - - - - Show distance to DX station in miles rather than kilometers. - - - Display dista&nce in miles - - - - - - - Show outgoing transmitted messages in the Rx frequency window. - - - &Tx messages to Rx frequency window - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -255,47 +255,6 @@ - - - - <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> - - - Monitor returns to last used frequency - - - - - - - Turns off automatic transmissions after sending a 73 or any other free -text message. - - - Di&sable Tx after sending 73 - - - - - - - Stop transmitting automatically after five periods. - - - Runaway Tx &watchdog - - - - - - - Automatic transmission mode. - - - Doubl&e-click on call sets Tx enable - - - @@ -309,6 +268,13 @@ text message. + + + + Decode at t = 52 s + + + @@ -368,6 +334,13 @@ quiet period when decoding is done. + + + + Single decode + + + @@ -378,17 +351,80 @@ quiet period when decoding is done. - - + + + + + + Tx watchdog: + + + tx_watchdog_spin_box + + + + + + + <html><head/><body><p>Number of minutes before unattended transmissions are aborted</p></body></html> + + + Disabled + + + minutes + + + + + + 6 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> + - Decode at t = 52 s + Monitor returns to last used frequency - - + + + + Automatic transmission mode. + - Single decode + Doubl&e-click on call sets Tx enable + + + + + + + Turns off automatic transmissions after sending a 73 or any other free +text message. + + + Di&sable Tx after sending 73 @@ -2376,10 +2412,7 @@ soundcard changes font_push_button decoded_text_font_push_button monitor_off_check_box - quick_call_check_box tx_QSY_check_box - disable_TX_on_73_check_box - watchdog_check_box decode_at_52s_check_box offset_Rx_freq_check_box CW_id_after_73_check_box @@ -2522,11 +2555,11 @@ soundcard changes + + + + - - - - diff --git a/mainwindow.cpp b/mainwindow.cpp index d9a7959ad..76fb0a535 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -143,6 +143,13 @@ namespace && ((type < 6 && msg_parts.contains ("73")) || (type == 6 && !msg_parts.filter ("73").isEmpty ())); } + + int ms_to_next_minute () + { + auto const& now = QDateTime::currentDateTime (); + auto const& time = now.time (); + return now.msecsTo (QDateTime {now.date (), QTime {time.hour (), time.minute (), 0}}.addSecs (60)); + } } //--------------------------------------------------- MainWindow constructor @@ -192,7 +199,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_inGain {0}, m_secID {0}, m_repeatMsg {0}, - m_watchdogLimit {6}, m_nSubMode {0}, m_nclearave {1}, m_pctx {0}, @@ -423,7 +429,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, // text message, send + empty text means send the current free // text message without change, !send + empty text means clear // the current free text message - qDebug () << "Free text UDP message - text:" << text << "send:" << send << "text empty:" << text.isEmpty (); if (0 == ui->tabWidget->currentIndex ()) { if (!text.isEmpty ()) { ui->tx5->setCurrentText (text); @@ -507,7 +512,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, }); setWindowTitle (program_title ()); - createStatusBar(); connect(&proc_jt9, &QProcess::readyReadStandardOutput, this, &MainWindow::readFromStdout); connect(&proc_jt9, static_cast (&QProcess::error), @@ -654,6 +658,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, readSettings(); //Restore user's setup params + createStatusBar(); + m_audioThread.start (m_audioThreadPriority); #ifdef WIN32 @@ -834,10 +840,42 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_wideGraph->setModeTx(m_modeTx); ui->sbSubmode->setValue(m_nSubMode); + connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::on_the_minute); + minuteTimer.setSingleShot (true); + minuteTimer.start (ms_to_next_minute ()); + // this must be the last statement of constructor if (!m_valid) throw std::runtime_error {"Fatal initialization exception"}; } +void MainWindow::on_the_minute () +{ + if (minuteTimer.isSingleShot ()) + { + minuteTimer.setSingleShot (false); + minuteTimer.start (60 * 1000); // run free + } + else + { + auto const& ms = ms_to_next_minute (); + if (qAbs (60 * 1000 - ms) > 1000) // correct drift + { + minuteTimer.setSingleShot (true); + minuteTimer.start (ms); + } + } + + if (m_repeatMsg < m_config.watchdog ()) ++m_repeatMsg; + if (!m_mode.startsWith ("WSPR") && m_config.watchdog () != 0) + { + updateProgressBarFormat (true); + } + else + { + updateProgressBarFormat (false); + } +} + //--------------------------------------------------- MainWindow destructor MainWindow::~MainWindow() { @@ -1392,7 +1430,7 @@ void MainWindow::updateProgressBarFormat (bool wd_in_use) { if (wd_in_use) { - progressBar->setFormat (QString {"%v/%m WD:%1"}.arg (m_watchdogLimit - m_repeatMsg)); + progressBar->setFormat (QString {"%v/%m WD:%1m"}.arg (m_config.watchdog () - m_repeatMsg)); } else { @@ -1400,28 +1438,8 @@ void MainWindow::updateProgressBarFormat (bool wd_in_use) } } -void MainWindow::mousePressEvent (QMouseEvent * e) -{ - if (!m_mode.startsWith ("WSPR") && m_mode!="Echo" && m_config.watchdog ()) { - m_repeatMsg = 0; // reset Tx watchdog - updateProgressBarFormat (true); - } - else { - updateProgressBarFormat (false); - } - QMainWindow::mousePressEvent (e); -} - void MainWindow::keyPressEvent (QKeyEvent * e) { - if (!m_mode.startsWith ("WSPR") && m_mode!="Echo" && m_config.watchdog ()) { - m_repeatMsg = 0; // reset Tx watchdog - updateProgressBarFormat (true); - } - else { - updateProgressBarFormat (false); - } - int n; switch(e->key()) { @@ -1570,17 +1588,35 @@ void MainWindow::statusChanged() << ui->rptSpinBox->value() << ";" << m_modeTx << endl; f.close(); } else { - msgBox("Cannot open \"" + f.fileName () + "\" for writing:" + f.errorString ()); + msgBox (tr ("Cannot open \"%1\" for writing: %2").arg (f.fileName ()).arg (f.errorString ())); } } -bool MainWindow::eventFilter(QObject *object, QEvent *event) //eventFilter() +bool MainWindow::eventFilter (QObject * object, QEvent * event) { - if (event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast(event); - MainWindow::keyPressEvent(keyEvent); - return QObject::eventFilter(object, event); - } + switch (event->type()) + { + case QEvent::KeyPress: + // fall through + case QEvent::MouseButtonPress: + if (m_repeatMsg && !m_mode.startsWith ("WSPR") && m_config.watchdog () != 0) { + m_repeatMsg = 0; // reset Tx watchdog + updateProgressBarFormat (true); + } + break; + + case QEvent::ChildAdded: + // ensure our child widgets get added to our event filter + add_child_to_event_filter (static_cast (event)->child ()); + break; + + case QEvent::ChildRemoved: + // ensure our child widgets get d=removed from our event filter + remove_child_from_event_filter (static_cast (event)->child ()); + break; + + default: break; + } return QObject::eventFilter(object, event); } @@ -1592,7 +1628,6 @@ void MainWindow::createStatusBar() //createStatusBar tx_status_label->setFrameStyle(QFrame::Panel | QFrame::Sunken); statusBar()->addWidget(tx_status_label); - mode_label->setAlignment(Qt::AlignHCenter); mode_label->setMinimumSize(QSize(80,18)); mode_label->setFrameStyle(QFrame::Panel | QFrame::Sunken); @@ -1610,7 +1645,7 @@ void MainWindow::createStatusBar() //createStatusBar statusBar()->addWidget(progressBar); progressBar->setMinimumSize (QSize {150, 18}); - updateProgressBarFormat (!m_mode.startsWith ("WSPR") && m_mode!="Echo" && m_config.watchdog ()); + updateProgressBarFormat (!m_mode.startsWith ("WSPR") && m_config.watchdog () != 0); } void MainWindow::subProcessFailed (QProcess * process, int exit_code, QProcess::ExitStatus status) @@ -1684,11 +1719,11 @@ void MainWindow::on_stopButton_clicked() //stopButton } } -void MainWindow::msgBox(QString t) //msgBox +void MainWindow::msgBox (QString const& text) { - msgBox0.setText(t); + msgBox0.setText (text); QApplication::alert (this); - msgBox0.exec(); + msgBox0.exec (); } void MainWindow::on_actionOnline_User_Guide_triggered() //Display manual @@ -2149,7 +2184,7 @@ void::MainWindow::fast_decode_done() out << message.mid(0,n-2) << endl; f.close(); } else { - msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ()); + msgBox (tr ("Cannot open \"%1\" for append: %2").arg (f.fileName ()).arg (f.errorString ())); } if(m_mode=="JT9" or m_mode=="JTMSK" or m_mode=="MSK144") { @@ -2236,7 +2271,7 @@ void MainWindow::readFromStdout() //readFromStdout out << t.mid(0,n-2) << endl; f.close(); } else { - msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ()); + msgBox (tr ("Cannot open \"%1\" for append: %2").arg (f.fileName ()).arg (f.errorString ())); } if (m_config.insert_blank () && m_blankLine) @@ -2485,13 +2520,23 @@ void MainWindow::guiUpdate() if (m_auto) auto_tx_mode (false); if(onAirFreq!=m_onAirFreq0) { m_onAirFreq0=onAirFreq; - QString t="Please choose another Tx frequency.\n"; - t+="WSJT-X will not knowingly transmit another\n"; - t+="mode in the WSPR sub-band on 30 m."; - msgBox(t); + auto const& message = tr ("Please choose another Tx frequency.\n" + "WSJT-X will not knowingly transmit another\n" + "mode in the WSPR sub-band on 30 m."); + QTimer::singleShot (0, [=] {msgBox (message);}); // don't block guiUpdate } } + if (!m_mode.startsWith ("WSPR") && m_config.watchdog() != 0 + && m_repeatMsg >= m_config. watchdog ()) { + m_bTxTime=false; + if (m_tune) stop_tuning (); + if (m_auto) auto_tx_mode (false); + QTimer::singleShot (0, [=] {msgBox ("Runaway Tx watchdog");}); // don't block guiUpdate + m_repeatMsg = 0; + updateProgressBarFormat (true); + } + float fTR=float((nsec%m_TRperiod))/m_TRperiod; // if(g_iptt==0 and ((m_bTxTime and fTR<0.4) or m_tune )) { if(g_iptt==0 and ((m_bTxTime and fTR<99) or m_tune )) { //### Allow late starts @@ -2622,7 +2667,9 @@ void MainWindow::guiUpdate() } else { - msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ()); + auto const& message = tr ("Cannot open \"%1\" for append: %2") + .arg (f.fileName ()).arg (f.errorString ()); + QTimer::singleShot (0, [=] {msgBox (message);}); // don't block guiUpdate } if (m_config.TX_messages ()) { @@ -2702,18 +2749,13 @@ void MainWindow::guiUpdate() if (g_iptt == 1 && m_iptt0 == 0) { auto const& current_message = QString::fromLatin1 (msgsent); - if(!m_mode.startsWith ("WSPR") && m_mode!="Echo" && m_config.watchdog ()) { - if (current_message == m_msgSent0) { - m_repeatMsg++; - } else { + if(!m_mode.startsWith ("WSPR") && m_config.watchdog () != 0) { + if (current_message != m_msgSent0) { m_repeatMsg=0; // in case we are auto sequencing m_msgSent0 = current_message; } updateProgressBarFormat (true); } - else { - updateProgressBarFormat (false); - } if(!m_tune) { QFile f {m_dataDir.absoluteFilePath ("ALL.TXT")}; @@ -2725,8 +2767,9 @@ void MainWindow::guiUpdate() << ": " << m_currentMessage << endl; f.close(); } else { - msgBox("Cannot open \"" + f.fileName () + "\" for append:" + - f.errorString ()); + auto const& message = tr ("Cannot open \"%1\" for append: %2") + .arg (f.fileName ()).arg(f.errorString ()); + QTimer::singleShot (0, [=] {msgBox (message);}); // don't block guiUpdate } } @@ -2844,7 +2887,8 @@ void MainWindow::startTx2() << m_currentMessage << " " + m_mode << endl; f.close(); } else { - msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ()); + msgBox (tr ("Cannot open \"%1\" for append: %2") + .arg (f.fileName ()).arg (f.errorString ())); } } } @@ -2870,17 +2914,6 @@ void MainWindow::stopTx2() on_stopTxButton_clicked(); m_nTx73=0; } - if (!m_mode.startsWith ("WSPR") && m_mode!="Echo" && m_config.watchdog()) { - if (m_repeatMsg >= m_watchdogLimit) { - on_stopTxButton_clicked(); - msgBox("Runaway Tx watchdog"); - m_repeatMsg = 0; - } - updateProgressBarFormat (true); - } - else { - updateProgressBarFormat (false); - } if(m_mode.startsWith ("WSPR") and m_ntr==-1 and !m_tuneup) { m_wideGraph->setWSPRtransmitted(); WSPR_scheduling (); @@ -4136,6 +4169,7 @@ void MainWindow::WSPR_config(bool b) auto_tx_label->setText (m_config.quick_call () ? "Auto-Tx-Enable Armed" : "Auto-Tx-Enable Disarmed"); m_bSimplex = false; } + auto_tx_label->setVisible (!b); enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook } @@ -5574,3 +5608,46 @@ void MainWindow::statusUpdate () const m_hisGrid); } } + +void MainWindow::childEvent (QChildEvent * e) +{ + if (e->child ()->isWidgetType ()) + { + switch (e->type ()) + { + case QEvent::ChildAdded: add_child_to_event_filter (e->child ()); break; + case QEvent::ChildRemoved: remove_child_from_event_filter (e->child ()); break; + default: break; + } + } + QMainWindow::childEvent (e); +} + +// add widget and any child widgets to our event filter so that we can +// take action on key press ad mouse press events anywhere in the main window +void MainWindow::add_child_to_event_filter (QObject * target) +{ + if (target && target->isWidgetType ()) + { + target->installEventFilter (this); + } + auto const& children = target->children (); + for (auto iter = children.begin (); iter != children.end (); ++iter) + { + add_child_to_event_filter (*iter); + } +} + +// recursively remove widget and any child widgets from our event filter +void MainWindow::remove_child_from_event_filter (QObject * target) +{ + auto const& children = target->children (); + for (auto iter = children.begin (); iter != children.end (); ++iter) + { + remove_child_from_event_filter (*iter); + } + if (target && target->isWidgetType ()) + { + target->removeEventFilter (this); + } +} diff --git a/mainwindow.h b/mainwindow.h index f2d04dc66..9822d3d94 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -113,9 +113,9 @@ public slots: protected: void keyPressEvent (QKeyEvent *) override; - void mousePressEvent (QMouseEvent *) override; - void closeEvent(QCloseEvent*) override; - bool eventFilter(QObject *object, QEvent *event) override; + void closeEvent(QCloseEvent *) override; + void childEvent(QChildEvent *) override; + bool eventFilter(QObject *, QEvent *) override; private slots: void on_tx1_editingFinished(); @@ -351,7 +351,6 @@ private: qint32 m_ncw; qint32 m_secID; qint32 m_repeatMsg; - qint32 m_watchdogLimit; qint32 m_nSubMode; qint32 m_nclearave; qint32 m_minSync; @@ -458,6 +457,7 @@ private: QTimer tuneATU_Timer; QTimer TxAgainTimer; QTimer RxQSYTimer; + QTimer minuteTimer; QString m_path; QString m_baseCall; @@ -514,7 +514,7 @@ private: void writeSettings(); void createStatusBar(); void updateStatusBar(); - void msgBox(QString t); + void msgBox(QString const&); void genStdMsgs(QString rpt); void clearDX (); void lookup(); @@ -558,6 +558,9 @@ private: void subProcessError (QProcess *, QProcess::ProcessError); void statusUpdate () const; void updateProgressBarFormat (bool wd_in_use); + void on_the_minute (); + void add_child_to_event_filter (QObject *); + void remove_child_from_event_filter (QObject *); }; extern int killbyname(const char* progName); diff --git a/mainwindow.ui b/mainwindow.ui index 63ab27659..3ca1ac77f 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -2,14 +2,6 @@ MainWindow - - - 0 - 0 - 896 - 565 - - WSJT-X by K1JT @@ -2284,14 +2276,6 @@ QPushButton[state="ok"] { - - - 0 - 0 - 896 - 21 - - File