mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-03-21 03:28:59 -04:00
highlighting callsigns, annotating callsigns, sort hounds on more criteria
This commit is contained in:
parent
9a7ae401e7
commit
8e6ca93259
@ -392,7 +392,22 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case NetworkMessage::AnnotationInfo: {
|
||||
QByteArray dx_call;
|
||||
bool sort_order_provided{false};
|
||||
quint32 sort_order{std::numeric_limits<quint32>::max()};
|
||||
in >> dx_call >> sort_order_provided >> sort_order;
|
||||
TRACE_UDP ("External Callsign Info:" << dx_call << "sort_order_provided:" << sort_order_provided
|
||||
<< "sort_order:" << sort_order);
|
||||
if (sort_order > 50000) sort_order = 50000;
|
||||
if (check_status(in) != Fail) {
|
||||
Q_EMIT
|
||||
self_->annotation_info(QString::fromUtf8(dx_call), sort_order_provided, sort_order);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore
|
||||
//
|
||||
// Note that although server heartbeat messages are not
|
||||
|
@ -123,7 +123,10 @@ public:
|
||||
, bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call
|
||||
, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
// this signal is emitted when network errors occur or if a host
|
||||
// this signal is emitted if the server has sent information about a callsign
|
||||
Q_SIGNAL void annotation_info (QString const& dx_call, bool sort_order_provided, quint32 sort_order);
|
||||
|
||||
// this signal is emitted when network errors occur or if a host
|
||||
// lookup fails
|
||||
Q_SIGNAL void error (QString const&) const;
|
||||
|
||||
|
@ -462,6 +462,14 @@
|
||||
* decoding may be impacted. A rough rule of thumb might be too
|
||||
* limit the number of active highlighting requests to no more
|
||||
* than 100.
|
||||
*
|
||||
* Using a callsign of "CLEARALL!" and anything for the
|
||||
* color values will clear the internal highlighting data. It will
|
||||
* NOT remove the highlighting on the screen, however. The exclamation
|
||||
* symbol is used to avoid accidental clearing of all highlighting
|
||||
* data via a decoded callsign, since an exclamation symbol is not
|
||||
* a valid character in a callsign.
|
||||
|
||||
*
|
||||
* The "Highlight last" field allows the sender to request that
|
||||
* all instances of "Callsign" in the last period only, instead
|
||||
@ -494,7 +502,33 @@
|
||||
* fields an empty value implies no change, for the quint32 Rx DF
|
||||
* and Frequency Tolerance fields the maximum quint32 value
|
||||
* implies no change. Invalid or unrecognized values will be
|
||||
* silently ignored.
|
||||
* silently ignored. NOTE that if a mode/submode change occurs and
|
||||
* the current frequency is NOT in the frequency table for that
|
||||
* mode, a frequency change (to the default frequency for that band
|
||||
* and mode) may occur.
|
||||
*
|
||||
* AnnotationInfo In 16 quint32
|
||||
* Id (unique key) utf8
|
||||
* DX Call utf8
|
||||
* Sort Order Provided bool
|
||||
* Sort Order quint32
|
||||
*
|
||||
* The server may send this message at any time. Sort orders can be used
|
||||
* for sorting hound callers when in Fox mode. A typical usage is to
|
||||
* "score" callsigns based on number of bands and/or modes worked using
|
||||
* an external logging program during a DXpedition, to be able to give
|
||||
* preference to calls that have not been worked before on any other
|
||||
* band or mode. An external program can watch decodes from wsjt-x,
|
||||
* then use this message to annotate the calls with a sort order. The
|
||||
* hound queue can be displayed by that sort order. *
|
||||
*
|
||||
* If 'sort order provided' is true, the message also specifies a numeric
|
||||
* sort order for the DX call.
|
||||
*
|
||||
* Invalid or unrecognized values will be silently ignored. A sort-order of
|
||||
* ffffffff will remove the sort-order value from the internal table.
|
||||
* Callsigns without a sort order will be valued at zero for sorting purposes
|
||||
* in the hound display.
|
||||
*/
|
||||
|
||||
#include <QDataStream>
|
||||
@ -526,6 +560,7 @@ namespace NetworkMessage
|
||||
HighlightCallsign,
|
||||
SwitchConfiguration,
|
||||
Configure,
|
||||
AnnotationInfo,
|
||||
maximum_message_type_ // ONLY add new message types
|
||||
// immediately before here
|
||||
};
|
||||
|
@ -40,6 +40,26 @@ void ActiveStations::changeFont (QFont const& font)
|
||||
updateGeometry ();
|
||||
}
|
||||
|
||||
void ActiveStations::clearStations() {
|
||||
m_textbuffer.clear();
|
||||
m_decodes_by_frequency.clear();
|
||||
}
|
||||
|
||||
void ActiveStations::addLine(QString line) {
|
||||
QString m_textbuffer = "";
|
||||
// "012700 -1 0.2 210 ~ KJ7COA JA2HGF -14"
|
||||
unsigned freq = line.mid(16, 4).toUInt();
|
||||
m_decodes_by_frequency[freq] = line;
|
||||
// show them in frequency order
|
||||
QMap<int, QString>::const_iterator i = m_decodes_by_frequency.constBegin();
|
||||
m_textbuffer.clear();
|
||||
while (i != m_decodes_by_frequency.constEnd()) {
|
||||
m_textbuffer.append(i.value());
|
||||
++i;
|
||||
}
|
||||
this->displayRecentStations(m_mode, m_textbuffer);
|
||||
}
|
||||
|
||||
void ActiveStations::read_settings ()
|
||||
{
|
||||
SettingsGroup group {settings_, "ActiveStations"};
|
||||
@ -60,8 +80,7 @@ void ActiveStations::write_settings ()
|
||||
settings_->setValue("WantedOnly",ui->cbWantedOnly->isChecked());
|
||||
}
|
||||
|
||||
void ActiveStations::displayRecentStations(QString mode, QString const& t)
|
||||
{
|
||||
void ActiveStations::setupUi(QString mode) {
|
||||
if(mode!=m_mode) {
|
||||
m_mode=mode;
|
||||
ui->cbReadyOnly->setText(" Ready only");
|
||||
@ -71,24 +90,37 @@ void ActiveStations::displayRecentStations(QString mode, QString const& t)
|
||||
ui->cbReadyOnly->setText("* CQ only");
|
||||
} else if(m_mode=="Q65-pileup") {
|
||||
ui->header_label2->setText(" N Freq Call Grid El Age(h)");
|
||||
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "Wanted only", nullptr));
|
||||
} else if(m_mode=="Fox Mode" || m_mode=="SuperFox Mode" ) {
|
||||
ui->header_label2->setText(" UTC dB DT Freq " + tr("Message"));
|
||||
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "My call only", nullptr));
|
||||
this->setClickOK(true);
|
||||
} else {
|
||||
ui->header_label2->setText(" N Call Grid Az S/N Freq Tx Age Pts");
|
||||
ui->label->setText("Rate:");
|
||||
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "Wanted only", nullptr));
|
||||
}
|
||||
bool b=(m_mode.left(3)=="Q65");
|
||||
ui->bandChanges->setVisible(!b);
|
||||
ui->cbReadyOnly->setVisible(m_mode!="Q65-pileup");
|
||||
ui->cbWantedOnly->setVisible(m_mode!="Q65-pileup");
|
||||
ui->label_2->setVisible(!b);
|
||||
ui->label_3->setVisible(!b);
|
||||
ui->score->setVisible(!b);
|
||||
ui->sbMaxRecent->setVisible(!b);
|
||||
bool is_fox_mode =(m_mode=="Fox Mode");
|
||||
ui->bandChanges->setVisible(!b && !is_fox_mode);
|
||||
ui->cbReadyOnly->setVisible(m_mode != "Q65-pileup" && !is_fox_mode);
|
||||
ui->cbWantedOnly->setVisible(m_mode != "Q65-pileup"); // this is used for "My call only" in Fox mode
|
||||
ui->label_2->setVisible(!b && !is_fox_mode);
|
||||
ui->label_3->setVisible(!b && !is_fox_mode);
|
||||
ui->score->setVisible(!b && !is_fox_mode);
|
||||
ui->sbMaxRecent->setVisible(!b && !is_fox_mode);
|
||||
|
||||
b=(m_mode!="Q65-pileup");
|
||||
b=(m_mode!="Q65-pileup" && !is_fox_mode);
|
||||
ui->sbMaxAge->setVisible(b);
|
||||
ui->label->setVisible(b);
|
||||
ui->rate->setVisible(b);
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveStations::displayRecentStations(QString mode, QString const& t)
|
||||
{
|
||||
setupUi(mode);
|
||||
|
||||
bool bClickOK=m_clickOK;
|
||||
m_clickOK=false;
|
||||
ui->RecentStationsPlainTextEdit->setPlainText(t);
|
||||
@ -143,7 +175,10 @@ void ActiveStations::on_textEdit_clicked()
|
||||
if(text!="") {
|
||||
int nline=text.left(2).toInt();
|
||||
if(QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) nline=-nline;
|
||||
emit callSandP(nline);
|
||||
if ("Fox Mode" != m_mode)
|
||||
emit callSandP(nline);
|
||||
else
|
||||
emit queueActiveWindowHound(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define ARRL_DIGI_H_
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMap>
|
||||
|
||||
class QSettings;
|
||||
class QFont;
|
||||
@ -20,6 +21,7 @@ public:
|
||||
explicit ActiveStations(QSettings *, QFont const&, QWidget * parent = 0);
|
||||
~ActiveStations();
|
||||
void displayRecentStations(QString mode, QString const&);
|
||||
void setupUi(QString display_mode);
|
||||
void changeFont (QFont const&);
|
||||
int maxRecent();
|
||||
int maxAge();
|
||||
@ -30,6 +32,8 @@ public:
|
||||
void setRate(int n);
|
||||
void setBandChanges(int n);
|
||||
void setScore(int n);
|
||||
void clearStations();
|
||||
void addLine(QString);
|
||||
|
||||
bool m_clickOK=false;
|
||||
bool m_bReadyOnly;
|
||||
@ -41,14 +45,16 @@ private:
|
||||
Q_SIGNAL void callSandP(int nline);
|
||||
Q_SIGNAL void activeStationsDisplay();
|
||||
Q_SIGNAL void cursorPositionChanged();
|
||||
Q_SIGNAL void queueActiveWindowHound(QString text);
|
||||
|
||||
Q_SLOT void on_cbReadyOnly_toggled(bool b);
|
||||
Q_SLOT void on_cbWantedOnly_toggled(bool b);
|
||||
Q_SLOT void on_textEdit_clicked();
|
||||
|
||||
// qint64 m_msec0=0;
|
||||
QString m_mode="";
|
||||
QSettings * settings_;
|
||||
QString m_textbuffer=""; // F/H mode band decodes
|
||||
QMap<int, QString> m_decodes_by_frequency; // store decodes for F/H band awareness by frequency
|
||||
|
||||
QScopedPointer<Ui::ActiveStations> ui;
|
||||
};
|
||||
|
@ -560,6 +560,22 @@ void DisplayText::displayHoundToBeCalled(QString t, bool bAtTop, QColor bg, QCol
|
||||
insertText(t, bg, fg, "", "", bAtTop ? QTextCursor::Start : QTextCursor::End);
|
||||
}
|
||||
|
||||
void DisplayText::setHighlightedHoundText(QString t) {
|
||||
QColor bg;
|
||||
QColor fg;
|
||||
highlight_types types{Highlight::Call};
|
||||
set_colours(m_config, &bg, &fg, types);
|
||||
// t is multiple lines of text, each line is a hound calling
|
||||
// iterate through each line and highlight the callsign
|
||||
auto lines = t.split(QChar('\n'), Qt::SkipEmptyParts);
|
||||
clear();
|
||||
foreach (auto line, lines)
|
||||
{
|
||||
auto fields = line.split(QChar(' '), Qt::SkipEmptyParts);
|
||||
insertText(line, bg, fg, fields.first(), QString{});
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void update_selection (QTextCursor& cursor, QColor const& bg, QColor const& fg)
|
||||
@ -619,6 +635,11 @@ void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (callsign == "CLEARALL!") // programmatic means of clearing all highlighting
|
||||
{
|
||||
highlighted_calls_.clear();
|
||||
return;
|
||||
}
|
||||
auto regexp = callsign;
|
||||
// allow for hashed callsigns and escape any regexp metacharacters
|
||||
QRegularExpression target {QString {"<?"}
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
double TRperiod, bool bSuperfox);
|
||||
void displayQSY(QString text);
|
||||
void displayHoundToBeCalled(QString t, bool bAtTop=false, QColor bg = QColor {}, QColor fg = QColor {});
|
||||
void setHighlightedHoundText(QString text);
|
||||
void new_period ();
|
||||
QString CQPriority(){return m_CQPriority;};
|
||||
qint32 m_points;
|
||||
|
@ -241,6 +241,7 @@ namespace
|
||||
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>;$]*"};
|
||||
// grid exact match excluding RR73
|
||||
QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"};
|
||||
QRegularExpression non_r_db_regexp {"\\A[-+]{1}[0-9]{1,2}\\z"};
|
||||
auto quint32_max = std::numeric_limits<quint32>::max ();
|
||||
constexpr int N_WIDGETS {38};
|
||||
constexpr int default_rx_audio_buffer_frames {-1}; // lets Qt decide
|
||||
@ -697,7 +698,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
|
||||
// initialize decoded text font and hook up font change signals
|
||||
// defer initialization until after construction otherwise menu fonts do not get set
|
||||
// with 50 ms delay we are on the save side
|
||||
// with 50 ms delay we are on the safe side
|
||||
QTimer::singleShot (50, this, SLOT (initialize_fonts ()));
|
||||
connect (&m_config, &Configuration::text_font_changed, [this] (QFont const& font) {
|
||||
set_application_font (font);
|
||||
@ -3103,9 +3104,15 @@ void MainWindow::on_actionActiveStations_triggered()
|
||||
m_ActiveStationsWidget->activateWindow();
|
||||
configActiveStations();
|
||||
connect(m_ActiveStationsWidget.data(), SIGNAL(callSandP(int)),this,SLOT(callSandP2(int)));
|
||||
// connect up another signal to handle clicks in the Activity window when in Fox mode
|
||||
connect(m_ActiveStationsWidget.data(), SIGNAL(queueActiveWindowHound(QString)),this,SLOT(queueActiveWindowHound2(QString)),static_cast<Qt::ConnectionType>(Qt::UniqueConnection));
|
||||
|
||||
connect(m_ActiveStationsWidget.data(), SIGNAL(activeStationsDisplay()),this,SLOT(ARRL_Digi_Display()));
|
||||
m_ActiveStationsWidget->setScore(m_score);
|
||||
if(m_mode=="Q65") m_ActiveStationsWidget->setRate(m_score);
|
||||
QString as_mode = m_mode;
|
||||
if(m_mode=="FT8" && SpecOp::FOX==m_specOp) as_mode="Fox Mode"; // TODO - active stations for hound mode?
|
||||
m_ActiveStationsWidget->setupUi(as_mode);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOpen_triggered() //Open File
|
||||
@ -3865,6 +3872,12 @@ void MainWindow::ARRL_Digi_Display()
|
||||
readWidebandDecodes();
|
||||
return;
|
||||
}
|
||||
if (m_mode == "Fox Mode") { // ARRL_Digi_Display can be shown for other modes
|
||||
if (m_ActiveStationsWidget != NULL) {
|
||||
m_ActiveStationsWidget->setClickOK(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
QMutableMapIterator<QString,RecentCall> icall(m_recentCall);
|
||||
QString deCall,deGrid;
|
||||
int age=0;
|
||||
@ -3935,10 +3948,53 @@ void MainWindow::ARRL_Digi_Display()
|
||||
t += (t1 + list[k] + "\n");
|
||||
if(i>=maxRecent) break;
|
||||
}
|
||||
if(m_ActiveStationsWidget!=NULL) m_ActiveStationsWidget->displayRecentStations(m_mode,t);
|
||||
bool is_fox_mode = (m_mode=="FT8" && m_specOp == SpecOp::FOX);
|
||||
if(m_ActiveStationsWidget!=NULL && !is_fox_mode) m_ActiveStationsWidget->displayRecentStations(m_mode,t);
|
||||
m_ActiveStationsWidget->setClickOK(true);
|
||||
}
|
||||
|
||||
void MainWindow::queueActiveWindowHound2(QString line) {
|
||||
// Active Window shows what's going on outside of current F/H display rules (calling below 1000Hz e.g.)
|
||||
// TODO should we allow calling a station that's calling another station, not us?
|
||||
if (m_mode == "FT8" and m_specOp == SpecOp::FOX) {
|
||||
// process the line to get the callsign
|
||||
QStringList w = line.split(' ', SkipEmptyParts);
|
||||
// make sure our call is the first in the list, or the station is CQing (not a directed CQ)
|
||||
if ( (w.size() > 7) &&
|
||||
(w[5] == m_config.my_callsign() || w[5] == "<"+m_config.my_callsign()+">" || w[5]=="CQ") &&
|
||||
( w[7].contains(grid_regexp) || w[7].contains(non_r_db_regexp) )){
|
||||
QString caller = w[6];
|
||||
QString grid = "";
|
||||
QString db = w[1];
|
||||
int db_i = w[1].toInt();
|
||||
db = (db_i >=0 ? "+":"") + QStringLiteral("%1").arg(db_i, (db_i >=0 ? 2:3), 10, QLatin1Char('0')); // +00, -01 etc.
|
||||
// houndcall rpt grid
|
||||
if (w[7].contains(grid_regexp)) grid = w[7];
|
||||
if (w[7].contains(non_r_db_regexp)) {
|
||||
LOG_INFO(QString("%1 called with signal report %2").arg(caller).arg(w[7]));
|
||||
}
|
||||
if (caller.length() > 2) {
|
||||
// make sure it's not already in the queue
|
||||
for ( QString hs : m_houndQueue) {
|
||||
if (hs.startsWith(caller)) {
|
||||
LOG_INFO(QString("%1 already in queue. Skipping").arg(hs));
|
||||
return;
|
||||
}
|
||||
}
|
||||
QString caller_rpt = (caller+" ").mid(0,12)+db;
|
||||
if (m_houndQueue.count() < MAX_HOUNDS_IN_QUEUE) {
|
||||
// add it to the queue
|
||||
m_houndQueue.enqueue(caller_rpt + " " + grid);
|
||||
refreshHoundQueueDisplay();
|
||||
// TODO: remove from active stations window too?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_INFO(QString("queueActiveWindowHound2 - skipping %1").arg(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::callSandP2(int n)
|
||||
{
|
||||
bool bCtrl = (n<0);
|
||||
@ -4035,12 +4091,20 @@ void MainWindow::activeWorked(QString call, QString band)
|
||||
void MainWindow::readFromStdout() //readFromStdout
|
||||
{
|
||||
bool bDisplayPoints = false;
|
||||
QString all_decodes;
|
||||
if(m_ActiveStationsWidget!=NULL) {
|
||||
bDisplayPoints=(m_mode=="FT4" or m_mode=="FT8") and
|
||||
(m_specOp==SpecOp::ARRL_DIGI or m_ActiveStationsWidget->isVisible());
|
||||
}
|
||||
while(proc_jt9.canReadLine()) {
|
||||
auto line_read = proc_jt9.readLine ();
|
||||
if (m_mode == "FT8" and m_specOp == SpecOp::FOX and m_ActiveStationsWidget != NULL) { // see if we should add this to ActiveStations window
|
||||
QString the_line = QString(line_read);
|
||||
if (!m_ActiveStationsWidget->wantedOnly() ||
|
||||
(the_line.contains(" " + m_config.my_callsign() + " ") ||
|
||||
the_line.contains(" <" + m_config.my_callsign() + "> ")))
|
||||
all_decodes.append(line_read);
|
||||
}
|
||||
if (auto p = std::strpbrk (line_read.constData (), "\n\r")) {
|
||||
// truncate before line ending chars
|
||||
line_read = line_read.left (p - line_read.constData ());
|
||||
@ -4124,6 +4188,10 @@ void MainWindow::readFromStdout() //readFromStdout
|
||||
if(m_TRperiod>=60) ntime=4;
|
||||
if (line_read.left(ntime) != m_tBlankLine && QString::fromUtf8(line_read.constData()).left(4).contains(QRegularExpression {"\\d\\d\\d\\d"})) {
|
||||
ui->decodedTextBrowser->new_period ();
|
||||
if (m_specOp == SpecOp::FOX and m_ActiveStationsWidget != NULL) { // clear the ActiveStations window
|
||||
m_ActiveStationsWidget->clearStations();
|
||||
m_ActiveStationsWidget->displayRecentStations("Fox Mode", "");
|
||||
}
|
||||
if (m_config.insert_blank ()
|
||||
&& SpecOp::FOX != m_specOp) {
|
||||
QString band;
|
||||
@ -4439,6 +4507,9 @@ void MainWindow::readFromStdout() //readFromStdout
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_mode == "FT8" and m_specOp == SpecOp::FOX and m_ActiveStationsWidget != NULL) {
|
||||
m_ActiveStationsWidget->addLine(all_decodes);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@ -4652,7 +4723,7 @@ void MainWindow::guiUpdate()
|
||||
m_bTxTime = (t2p >= tx1) and (t2p < tx2);
|
||||
if(m_mode=="Echo") m_bTxTime = m_bTxTime and m_bEchoTxOK;
|
||||
if(m_mode=="FT8" and ui->tx5->currentText().contains("/B ")) {
|
||||
//FT8 beacon transmissiion from Tx5 only at top of a UTC minute
|
||||
//FT8 beacon transmission from Tx5 only at top of a UTC minute
|
||||
double t4p=fmod(tsec,4*m_TRperiod);
|
||||
if(t4p >= 30.0) m_bTxTime=false;
|
||||
}
|
||||
@ -4731,7 +4802,7 @@ void MainWindow::guiUpdate()
|
||||
ui->TxFreqSpinBox->setValue(750); //SuperFox transmits at 750 Hz
|
||||
} else {
|
||||
if (ui->TxFreqSpinBox->value() > 900) {
|
||||
ui->TxFreqSpinBox->setValue(300);
|
||||
ui->TxFreqSpinBox->setValue(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7226,7 +7297,7 @@ void MainWindow::on_actionFT8_triggered()
|
||||
ui->rh_decodes_title_label->setText(tr ("Rx Frequency"));
|
||||
if(SpecOp::FOX==m_specOp) {
|
||||
ui->lh_decodes_title_label->setText(tr ("Stations calling DXpedition %1").arg (m_config.my_callsign()));
|
||||
ui->lh_decodes_headings_label->setText( "Call Grid dB Freq Dist Age Continent");
|
||||
ui->lh_decodes_headings_label->setText( "Call Grid dB Freq Dist Age Cont Score");
|
||||
} else {
|
||||
ui->lh_decodes_title_label->setText(tr ("Band Activity"));
|
||||
ui->lh_decodes_headings_label->setText( " UTC dB DT Freq " + tr ("Message"));
|
||||
@ -7252,16 +7323,18 @@ void MainWindow::on_actionFT8_triggered()
|
||||
if(m_config.superFox()) {
|
||||
ui->TxFreqSpinBox->setValue(750); //SuperFox transmits at 750 Hz
|
||||
} else {
|
||||
ui->TxFreqSpinBox->setValue(300);
|
||||
ui->TxFreqSpinBox->setValue(500);
|
||||
}
|
||||
// 01234567890123456789012345678901234567
|
||||
displayWidgets(nWidgets("11101000010011100001000000000010000000"));
|
||||
displayWidgets(nWidgets("11101000010011100001000000000011000000"));
|
||||
ui->cbRxAll->setText(tr("Show Already Worked"));
|
||||
if(m_config.superFox()) {
|
||||
ui->labDXped->setText(tr ("Super Fox"));
|
||||
} else {
|
||||
ui->labDXped->setText(tr ("Fox"));
|
||||
}
|
||||
on_fox_log_action_triggered();
|
||||
if (m_ActiveStationsWidget) m_ActiveStationsWidget->setClickOK(true); // allow clicks
|
||||
}
|
||||
if(SpecOp::HOUND == m_specOp) {
|
||||
ui->houndButton->setChecked(true);
|
||||
@ -7272,6 +7345,7 @@ void MainWindow::on_actionFT8_triggered()
|
||||
ui->cbHoldTxFreq->setChecked(true);
|
||||
// 01234567890123456789012345678901234567
|
||||
displayWidgets(nWidgets("11101000010011000001000000000011000000"));
|
||||
ui->cbRxAll->setText(tr("Rx All Freqs"));
|
||||
if(m_config.superFox()) {
|
||||
ui->labDXped->setText(tr ("Super Hound"));
|
||||
ui->cbRxAll->setEnabled(false);
|
||||
@ -7288,6 +7362,7 @@ void MainWindow::on_actionFT8_triggered()
|
||||
ui->txb4->setEnabled(false);
|
||||
ui->txb5->setEnabled(false);
|
||||
ui->txb6->setEnabled(false);
|
||||
if (m_ActiveStationsWidget) m_ActiveStationsWidget->setClickOK(false);
|
||||
} else {
|
||||
switch_mode (Modes::FT8);
|
||||
}
|
||||
@ -9995,15 +10070,21 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB)
|
||||
* 2: Grid
|
||||
* 3: SNR (reverse order)
|
||||
* 4: Distance (reverse order)
|
||||
* 5: Age (reverse order)
|
||||
* 6: Continent
|
||||
* 7: User defined (reverse order)
|
||||
*
|
||||
*/
|
||||
|
||||
QMap<QString,QString> map;
|
||||
QStringList lines,lines2;
|
||||
QString msg,houndCall,t1;
|
||||
QString ABC{"ABCDEFGHIJKLMNOPQRSTUVWXYZ _"};
|
||||
QList<int> reverse_sorted{3,4,5,6};
|
||||
QString Continents{" AF AN AS EU NA OC SA UN "}; // matches what we get from AD1C's country list
|
||||
QList<int> list;
|
||||
int i,j,k,n,nlines;
|
||||
bool bReverse=(isort >= 3);
|
||||
bool bReverse = reverse_sorted.contains(isort);
|
||||
|
||||
isort=qAbs(isort);
|
||||
// Save only the most recent transmission from each caller.
|
||||
@ -10012,7 +10093,7 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB)
|
||||
for(i=0; i<nlines; i++) {
|
||||
msg=lines.at(i); //key = callsign
|
||||
if(msg.mid(13,1)==" ") msg=msg.mid(0,13) + "...." + msg.mid(17);
|
||||
houndCall=msg.split(" ").at(0); //value = "call grid snr freq dist age"
|
||||
houndCall=msg.split(" ").at(0); //value = "call grid snr freq dist age continent user-defined
|
||||
map[houndCall]=msg;
|
||||
}
|
||||
|
||||
@ -10020,16 +10101,43 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB)
|
||||
t="";
|
||||
for(auto a: map.keys()) {
|
||||
t1=map[a].split(" ",SkipEmptyParts).at(2);
|
||||
// add the user-defined value to the end of the line. Example:
|
||||
// JJ0NCC PM97 15 2724 7580 2 AS 67
|
||||
// PY7ZZ HI21 -13 1673 10549 1 SA -
|
||||
|
||||
QString annotated_value_s{" - "}; // default
|
||||
qint32 annotated_value = 0;
|
||||
|
||||
if (m_annotated_callsigns.contains(a)) {
|
||||
annotated_value = m_annotated_callsigns.value(a);
|
||||
annotated_value_s = QString::number(annotated_value);
|
||||
}
|
||||
|
||||
map[a] += QString(" %1").arg(annotated_value_s, 8);
|
||||
int nsnr=t1.toInt(); // get snr
|
||||
if(nsnr <= max_dB) { // keep only if snr in specified range
|
||||
if(isort==1) t += map[a] + "\n";
|
||||
if(isort==3 or isort==4) {
|
||||
i=2; // sort Hound calls by snr
|
||||
if(isort==4) i=4; // sort Hound calls by distance
|
||||
if (isort==3 or isort==4 or isort==5) { // numeric ones: snr, distance, age
|
||||
if (isort==3)
|
||||
i=2; // sort Hound calls by snr
|
||||
else
|
||||
i=isort; // part of the line that we want
|
||||
t1=map[a].split(" ",SkipEmptyParts).at(i);
|
||||
n=1000*(t1.toInt()+100) + j; // pack (snr or dist) and index j into n
|
||||
n=1000*(t1.toInt()+100) + j; // pack (snr or dist or age) and index j into n
|
||||
list.insert(j,n); // add n to list at [j]
|
||||
}
|
||||
if (isort == 6) { // sort by continent
|
||||
i = 6;
|
||||
QStringList parts = map[a].split(" ", SkipEmptyParts);
|
||||
if (parts.size() <= i + 1) {
|
||||
n = j;
|
||||
} else {
|
||||
QString cont = map[a].split(" ", SkipEmptyParts).at(i);
|
||||
int cont_n = Continents.indexOf(" " + cont + " ");
|
||||
n = 1000 + 1000 * cont_n + j; // index may return -1, so add 1000 to make it positive
|
||||
}
|
||||
list.insert(j, n);
|
||||
}
|
||||
|
||||
if(isort==2) { // sort Hound calls by grid
|
||||
t1=map[a].split(" ",SkipEmptyParts).at(1);
|
||||
@ -10041,6 +10149,11 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB)
|
||||
list.insert(j,n); // add n to list at [j]
|
||||
}
|
||||
|
||||
if(isort==7) { // annotated value provided by external app
|
||||
n = 1000 + 1000 * std::max((qint32) 0, annotated_value) + j;
|
||||
list.insert(j, n);
|
||||
}
|
||||
|
||||
lines2.insert(j,map[a]); // add map[a] to lines2 at [j]
|
||||
j++;
|
||||
}
|
||||
@ -10109,14 +10222,16 @@ void MainWindow::selectHound(QString line, bool bTopQueue)
|
||||
|
||||
m_houndCallers=m_houndCallers.remove(line+"\n"); // Remove t from sorted Hound list
|
||||
m_nSortedHounds--;
|
||||
ui->decodedTextBrowser->setText(m_houndCallers); // Populate left window with Hound callers
|
||||
ui->decodedTextBrowser->setHighlightedHoundText(m_houndCallers); // Populate left window with Hound callers
|
||||
QString t1=houndCall + " ";
|
||||
QString t2=rpt;
|
||||
QString t1_with_grid;
|
||||
if(rpt.mid(0,1) != "-" and rpt.mid(0,1) != "+") t2="+" + rpt;
|
||||
if(t2.length()==2) t2=t2.mid(0,1) + "0" + t2.mid(1,1);
|
||||
t1=t1.mid(0,12) + t2;
|
||||
ui->houndQueueTextBrowser->displayHoundToBeCalled(t1, bTopQueue); // Add hound call and rpt to tb4
|
||||
// display the callers, highlighting calls if necessary
|
||||
ui->houndQueueTextBrowser->insertText(bTopQueue ? t1 + "\n" : t1, QColor{}, QColor{}, houndCall, "", bTopQueue ? QTextCursor::Start : QTextCursor::End);
|
||||
|
||||
t1_with_grid=t1 + " " + houndGrid; // Append the grid
|
||||
|
||||
if (bTopQueue)
|
||||
@ -10131,6 +10246,9 @@ void MainWindow::selectHound(QString line, bool bTopQueue)
|
||||
QTextCursor cursor = ui->houndQueueTextBrowser->textCursor();
|
||||
cursor.setPosition(0); // Scroll to top of list
|
||||
ui->houndQueueTextBrowser->setTextCursor(cursor);
|
||||
cursor = ui->decodedTextBrowser->textCursor();
|
||||
cursor.setPosition(0); // Highlighting happens in the forward direction
|
||||
ui->decodedTextBrowser->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -10214,8 +10332,11 @@ void MainWindow::houndCallers()
|
||||
if(t.length()>30) {
|
||||
m_isort=ui->comboBoxHoundSort->currentIndex();
|
||||
QString t1=sortHoundCalls(t,m_isort,m_max_dB);
|
||||
ui->decodedTextBrowser->setText(t1);
|
||||
ui->decodedTextBrowser->setHighlightedHoundText(t1);
|
||||
}
|
||||
QTextCursor cursor = ui->decodedTextBrowser->textCursor();
|
||||
cursor.setPosition(0); // Set scroll at top, in preparation for highlighting messages
|
||||
ui->decodedTextBrowser->setTextCursor(cursor);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
@ -10252,7 +10373,7 @@ void MainWindow::updateFoxQSOsInProgressDisplay()
|
||||
QString hc = m_foxQSOinProgress.at(i);
|
||||
QString status = m_foxQSO[hc].ncall > m_maxStrikes ? QString(" (rx) ") : QString(" ");
|
||||
QString str = (hc + " ").left(13) + QString::number(m_foxQSO[hc].ncall) + status;
|
||||
ui->foxTxListTextBrowser->displayHoundToBeCalled(str);
|
||||
ui->foxTxListTextBrowser->insertText(str, QColor{}, QColor{}, hc, "", QTextCursor::End);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10350,7 +10471,7 @@ list1Done:
|
||||
m_foxQSO[hc].rcvd = -99; //Have not received R+rpt
|
||||
m_foxQSO[hc].tFoxRrpt = -1; //Have not received R+rpt
|
||||
m_foxQSO[hc].tFoxTxRR73 = -1; //Have not sent RR73
|
||||
rm_tb4(hc); //Remove this Hound from tb4
|
||||
refreshHoundQueueDisplay();
|
||||
|
||||
if(list2.size()==m_Nslots) {
|
||||
break;
|
||||
@ -10480,24 +10601,13 @@ void MainWindow::update_foxLogWindow_rate()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::rm_tb4(QString houndCall)
|
||||
void MainWindow::refreshHoundQueueDisplay()
|
||||
{
|
||||
if(houndCall=="") return;
|
||||
QString t="";
|
||||
QString tb4=ui->houndQueueTextBrowser->toPlainText();
|
||||
QStringList list=tb4.split("\n");
|
||||
int n=list.size();
|
||||
int j=0;
|
||||
for (int i=0; i<n; i++) {
|
||||
if(j>0) t += "\n";
|
||||
QString line=list.at(i);
|
||||
if(!line.contains(houndCall + " ")) {
|
||||
j++;
|
||||
t += line;
|
||||
}
|
||||
ui->houndQueueTextBrowser->clear();
|
||||
for (QString line: m_houndQueue) {
|
||||
auto hc = line.mid(0, 12).trimmed();
|
||||
ui->houndQueueTextBrowser->insertText(line, QColor{}, QColor{}, hc, "", QTextCursor::End);
|
||||
}
|
||||
t.replace("\n\n","\n");
|
||||
ui->houndQueueTextBrowser->setText(t);
|
||||
}
|
||||
|
||||
void MainWindow::doubleClickOnFoxQueue(Qt::KeyboardModifiers modifiers)
|
||||
@ -10521,14 +10631,9 @@ void MainWindow::doubleClickOnFoxQueue(Qt::KeyboardModifiers modifiers)
|
||||
}
|
||||
}
|
||||
m_houndQueue.prepend(houndLine);
|
||||
ui->houndQueueTextBrowser->clear();
|
||||
for (QString line: m_houndQueue)
|
||||
{
|
||||
ui->houndQueueTextBrowser->displayHoundToBeCalled(line.mid(0,16), false);
|
||||
}
|
||||
refreshHoundQueueDisplay();
|
||||
} else
|
||||
{
|
||||
rm_tb4(houndCall);
|
||||
writeFoxQSO(" Del: " + houndCall);
|
||||
QQueue <QString> tmpQueue;
|
||||
while (!m_houndQueue.isEmpty())
|
||||
@ -10538,6 +10643,7 @@ void MainWindow::doubleClickOnFoxQueue(Qt::KeyboardModifiers modifiers)
|
||||
if (hc != houndCall) tmpQueue.enqueue(t);
|
||||
}
|
||||
m_houndQueue.swap(tmpQueue);
|
||||
refreshHoundQueueDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
@ -10559,7 +10665,7 @@ void MainWindow::doubleClickOnFoxInProgress(Qt::KeyboardModifiers modifiers)
|
||||
void MainWindow::foxQueueTopCallCommand()
|
||||
{
|
||||
m_decodedText2 = true;
|
||||
if(SpecOp::FOX==m_specOp && m_decodedText2 && m_houndQueue.count() < 10)
|
||||
if(SpecOp::FOX==m_specOp && m_decodedText2 && m_houndQueue.count() < MAX_HOUNDS_IN_QUEUE)
|
||||
{
|
||||
|
||||
QTextCursor cursor = ui->decodedTextBrowser->textCursor();
|
||||
@ -10687,7 +10793,7 @@ void MainWindow::foxTest()
|
||||
hc1=line.mid(i0+6);
|
||||
int i1=hc1.indexOf(" ");
|
||||
hc1=hc1.mid(0,i1);
|
||||
rm_tb4(hc1);
|
||||
|
||||
writeFoxQSO(" Del: " + hc1);
|
||||
QQueue<QString> tmpQueue;
|
||||
while(!m_houndQueue.isEmpty()) {
|
||||
@ -10696,6 +10802,7 @@ void MainWindow::foxTest()
|
||||
if(hc != hc1) tmpQueue.enqueue(t);
|
||||
}
|
||||
m_houndQueue.swap(tmpQueue);
|
||||
refreshHoundQueueDisplay();
|
||||
}
|
||||
if(line.contains("Rx:")) {
|
||||
msg=line.mid(37+6);
|
||||
@ -10870,13 +10977,18 @@ void MainWindow::set_mode (QString const& mode)
|
||||
else if ("Echo" == mode) on_actionEcho_triggered ();
|
||||
}
|
||||
|
||||
void MainWindow::configActiveStations()
|
||||
{
|
||||
if(m_ActiveStationsWidget!=NULL and (m_mode=="Q65" or m_mode=="FT4" or m_mode=="FT8")) {
|
||||
if(m_specOp==SpecOp::Q65_PILEUP) {
|
||||
m_ActiveStationsWidget->displayRecentStations("Q65-pileup","");
|
||||
void MainWindow::configActiveStations() {
|
||||
if (m_ActiveStationsWidget != NULL and (m_mode == "Q65" or m_mode == "FT4" or m_mode == "FT8")) {
|
||||
if (m_specOp == SpecOp::Q65_PILEUP) {
|
||||
m_ActiveStationsWidget->displayRecentStations("Q65-pileup", "");
|
||||
} else {
|
||||
m_ActiveStationsWidget->displayRecentStations(m_mode,"");
|
||||
if (m_specOp == SpecOp::FOX)
|
||||
if (m_config.superFox())
|
||||
m_ActiveStationsWidget->displayRecentStations("SuperFox Mode", "");
|
||||
else
|
||||
m_ActiveStationsWidget->displayRecentStations("Fox Mode", "");
|
||||
else
|
||||
m_ActiveStationsWidget->displayRecentStations(m_mode, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@
|
||||
#define MAX_NUM_SYMBOLS 250
|
||||
#define TX_SAMPLE_RATE 48000
|
||||
#define NRING 3456000
|
||||
#define MAX_HOUNDS_IN_QUEUE 10
|
||||
|
||||
extern int volatile itone[MAX_NUM_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
@ -345,6 +346,8 @@ private slots:
|
||||
, bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call
|
||||
, QString const& dx_grid, bool generate_messages);
|
||||
void callSandP2(int nline);
|
||||
void refreshHoundQueueDisplay();
|
||||
void queueActiveWindowHound2(QString text);
|
||||
|
||||
private:
|
||||
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
|
||||
@ -702,6 +705,7 @@ private:
|
||||
|
||||
QMap<QString,FoxQSO> m_foxQSO; //Key = HoundCall, value = parameters for QSO in progress
|
||||
QMap<QString,QString> m_loggedByFox; //Key = HoundCall, value = logged band
|
||||
QMap<QString,qint32> m_annotated_callsigns; //Key = HoundCall, value = provided by api call
|
||||
|
||||
struct FixupQSO //Info for fixing Fox's log from file "FoxQSO.txt"
|
||||
{
|
||||
|
@ -2375,6 +2375,21 @@ Double-click to reset to the standard 73 message</string>
|
||||
<string>Distance</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Age</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Continent</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Score</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" rowspan="10">
|
||||
|
Loading…
Reference in New Issue
Block a user