Performance improvements to decode highlighting

The Highlight  Callsign (13)  UDP message now  operates in  a slightly
different way.  The  "Highlight last" field, when  true valued, causes
all  instances of  the specified  callsign  to be  highlighted in  the
decoding  period. This  allows external  applications to  highlight DX
callsigns even when  multiple stations are calling  them.  Before this
was  unlikely to  work since  the external  application would  have to
respond to  Decode (2) UDP  messages exceedingly quickly  to guarantee
successful highlighting  before another decode  with the same  DX call
was  printed.   There  should  be  no  changes  required  to  external
applications acting  as servers  to the  WSJT-X UDP  Message Protocol,
although  using  the  version  of the  Highlight  Callsign  (13)  with
"Highlight   last"  should   not  be   required  for   adhoc  callsign
highlighting. It should be reserved for commonly recurring targets and
limited to  no more than 100  active highlighting requests at  any one
time, otherwise there may be performance impacts on WSJT-X.
This commit is contained in:
Bill Somerville 2020-05-24 16:33:14 +01:00
parent b31dfba67b
commit c6688534cd
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
3 changed files with 87 additions and 45 deletions

View File

@ -447,16 +447,20 @@
* The server may send this message at any time. The message
* specifies the background and foreground color that will be
* used to highlight the specified callsign in the decoded
* messages printed in the Band Activity panel. The WSJT-X
* messages printed in the Band Activity panel. The WSJT-X
* clients maintain a list of such instructions and apply them to
* all decoded messages in the band activity window. To clear
* highlighting send an invalid QColor value for either or both
* of the background and foreground fields.
* and cancel highlighting send an invalid QColor value for
* either or both of the background and foreground fields. When
* using this mode the total number of callsign highlighting
* requests should be limited otherwise the performance of WSJT-X
* decoding may be impacted. A rough rule of thumb might be too
* limit the number of active highlighting requests to no more
* than 100.
*
* The "Highlight last" field allows the sender to request that
* the last instance only instead of all instances of the
* specified call be highlighted or have it's highlighting
* cleared.
* all instances of "Callsign" in the last period only, instead
* of all instances in all periods, be highlighted.
*
*
* SwitchConfiguration In 14 quint32

View File

@ -497,60 +497,92 @@ namespace
{
void update_selection (QTextCursor& cursor, QColor const& bg, QColor const& fg)
{
if (!cursor.isNull ())
QTextCharFormat format {cursor.charFormat ()};
if (bg.isValid ())
{
QTextCharFormat format {cursor.charFormat ()};
if (bg.isValid ())
{
format.setBackground (bg);
}
else
{
format.clearBackground ();
}
if (fg.isValid ())
{
format.setForeground (fg);
}
else
{
format.clearForeground ();
}
cursor.mergeCharFormat (format);
format.setBackground (bg);
}
else
{
format.clearBackground ();
}
if (fg.isValid ())
{
format.setForeground (fg);
}
else
{
format.clearForeground ();
}
cursor.mergeCharFormat (format);
}
void reset_selection (QTextCursor& cursor)
{
if (!cursor.isNull ())
// restore previous text format, we rely on the text
// char format at he start of the selection being the
// old one which should be the case
auto c2 = cursor;
c2.setPosition (c2.selectionStart ());
cursor.setCharFormat (c2.charFormat ());
}
}
namespace
{
QString get_timestamp (QTextCursor& cursor)
{
QString timestamp;
if (cursor.movePosition (QTextCursor::PreviousCharacter)
&& cursor.movePosition (QTextCursor::StartOfLine)
&& cursor.movePosition (QTextCursor::EndOfWord, QTextCursor::KeepAnchor)
&& cursor.hasSelection ())
{
// restore previous text format, we rely on the text
// char format at he start of the selection being the
// old one which should be the case
auto c2 = cursor;
c2.setPosition (c2.selectionStart ());
cursor.setCharFormat (c2.charFormat ());
timestamp = cursor.selectedText ();
cursor.movePosition (QTextCursor::StartOfLine);
}
return timestamp;
}
}
void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
QColor const& fg, bool last_only)
QColor const& fg, bool last_period_only)
{
// qDebug () << "DisplayText::highlight_callsign: callsign:" << callsign << "last period:" << last_period_only;
if (!callsign.size ())
{
return;
}
QRegularExpression target {QString {"<?"} + callsign + QString {">?"}, QRegularExpression::DontCaptureOption};
QTextCharFormat old_format {currentCharFormat ()};
QTextCursor cursor {document ()};
if (last_only)
if (last_period_only)
{
// highlight each instance of the given callsign (word) in the
// current period
cursor.movePosition (QTextCursor::End);
cursor = document ()->find (callsign, cursor
, QTextDocument::FindBackward | QTextDocument::FindWholeWords);
if (bg.isValid () || fg.isValid ())
QTextCursor period_start {cursor};
QTextCursor prior {cursor};
auto period_timestamp = get_timestamp (period_start);
while (period_timestamp.size () && period_timestamp == get_timestamp (prior))
{
update_selection (cursor, bg, fg);
period_start = prior;
}
else
while (!cursor.isNull () && cursor > period_start)
{
reset_selection (cursor);
cursor = document ()->find (target, cursor
, QTextDocument::FindBackward | QTextDocument::FindWholeWords);
if (!cursor.isNull () && cursor.hasSelection ())
{
if (bg.isValid () || fg.isValid ())
{
update_selection (cursor, bg, fg);
}
else
{
reset_selection (cursor);
}
}
}
}
else
@ -569,8 +601,11 @@ void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
}
while (!cursor.isNull ())
{
cursor = document ()->find (callsign, cursor, QTextDocument::FindWholeWords);
update_selection (cursor, bg, fg);
cursor = document ()->find (target, cursor, QTextDocument::FindWholeWords);
if (!cursor.isNull () && cursor.hasSelection ())
{
update_selection (cursor, bg, fg);
}
}
}
else if (pos != highlighted_calls_.end ())
@ -579,8 +614,11 @@ void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
QTextCursor cursor {document ()};
while (!cursor.isNull ())
{
cursor = document ()->find (callsign, cursor, QTextDocument::FindWholeWords);
reset_selection (cursor);
cursor = document ()->find (target, cursor, QTextDocument::FindWholeWords);
if (!cursor.isNull () && cursor.hasSelection ())
{
reset_selection (cursor);
}
}
}
}

View File

@ -43,7 +43,7 @@ public:
Q_SLOT void appendText (QString const& text, QColor bg = QColor {}, QColor fg = QColor {}
, QString const& call1 = QString {}, QString const& call2 = QString {});
Q_SLOT void erase ();
Q_SLOT void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_only);
Q_SLOT void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_period_only);
private:
void mouseDoubleClickEvent (QMouseEvent *) override;