Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ May 2026 - 2.5.2
- Enhancement: Move Comment field from Comment tab to QSO tab (Closes #1020) (TNX EA5WA)
- New feature: Selection of language (Closes #9) (TNX EA5WA)
- New feature: Set CQ zone from DXCC when adding QSO (TNX YL3GBC)
- New feature: Show a "New Locator" indicator when the DX locator is new on the current band or via satellite (Closes #1035) (TNX EA5WA)
- Translations: Latvian (TNX YL3GBC & YL3AUG)

May 2026 - 2.5.1
Expand Down
59 changes: 59 additions & 0 deletions src/dataproxy_sqlite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,65 @@ QVariantList DataProxy_SQLite::getQSOsForLocator(const QString &_locator, const
return result;
}

bool DataProxy_SQLite::isNewGridOnBand(const QString &_grid, const int _bandId, const int _logNumber, const QString &_prop, const int _excludeQsoId)
{
//qDebug() << Q_FUNC_INFO << " - grid: " << _grid << " bandId: " << _bandId << " log: " << _logNumber << " prop: " << _prop << " exclude: " << _excludeQsoId;
logEvent(Q_FUNC_INFO, "Start", Devel);

const QString grid = _grid.trimmed().toUpper();
const bool isSat = (_prop.trimmed().toUpper() == "SAT");

// Satellite stats are kept apart and are not band-dependent; terrestrial needs a valid band.
if (grid.isEmpty() || _logNumber < 0 || (!isSat && _bandId <= 0))
{
logEvent(Q_FUNC_INFO, "END-1", Debug);
return false;
}

QStringList where;
where << "lognumber = :lognumber" << "UPPER(gridsquare) LIKE :gridprefix";
if (isSat)
{
// Count only satellite QSOs, regardless of band (separate statistics).
where << "prop_mode = 'SAT'";
}
else
{
// Count QSOs on this band, excluding any made via satellite.
where << "bandid = :bandid" << "COALESCE(prop_mode,'') <> 'SAT'";
}
if (_excludeQsoId > 0)
where << "id <> :excludeid";

const QString queryString = "SELECT COUNT(id) FROM log WHERE " + where.join(" AND ");

QSqlQuery query;
if (!query.prepare(queryString))
{
logEvent(Q_FUNC_INFO, "END-2", Debug);
return false;
}
query.bindValue(":lognumber", _logNumber);
query.bindValue(":gridprefix", grid + "%");
if (!isSat)
query.bindValue(":bandid", _bandId);
if (_excludeQsoId > 0)
query.bindValue(":excludeid", _excludeQsoId);

if (query.exec() && query.next() && query.isValid())
{
const int count = query.value(0).toInt();
query.finish();
logEvent(Q_FUNC_INFO, "END-3", Debug);
return (count == 0);
}

emit queryError(Q_FUNC_INFO, query.lastError().databaseText(), query.lastError().text(), query.lastQuery());
query.finish();
logEvent(Q_FUNC_INFO, "END-4", Debug);
return false;
}

bool DataProxy_SQLite::QRZCOMModifyFullLog(const int _currentLog)
{
//qDebug() << Q_FUNC_INFO << " -" << QString::number(_currentLog);
Expand Down
5 changes: 5 additions & 0 deletions src/dataproxy_sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ class DataProxy_SQLite : public QObject
QStringList getFilteredLocators(const QString &_band, const QString &_mode, const QString &_prop, const QString &_sat, bool _confirmed = false);
// Returns list of {id, callsign, band, mode} maps for QSOs matching a locator prefix and current filters
QVariantList getQSOsForLocator(const QString &_locator, const QString &_band, const QString &_mode, const QString &_prop, const QString &_sat, bool _confirmed = false);
// Returns true if no QSO in the given log already has a gridsquare starting with _grid (4-char field).
// When _prop is "SAT" the check is band-independent and only considers satellite QSOs (separate stats);
// otherwise it is restricted to _bandId and excludes satellite QSOs.
// _excludeQsoId lets the caller ignore one QSO (e.g. the one being edited); pass -1 to exclude none.
bool isNewGridOnBand(const QString &_grid, const int _bandId, const int _logNumber, const QString &_prop, const int _excludeQsoId = -1);
//bool updateAwardWAZ();
// QRZ.com
bool QRZCOMModifyFullLog(const int _currentLog); // Mark all the log as modified to be sent to QRZ.com
Expand Down
22 changes: 21 additions & 1 deletion src/inputwidgets/mainwindowinputqso.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void MainWindowInputQSO::createUI()
qthLabel->setText(tr("QTH"));
qthLabel->setAlignment(Qt::AlignCenter);

QLabel *locLabel = new QLabel(this);
locLabel = new QLabel(this);
locLabel->setText(tr("DX Locator"));
locLabel->setAlignment(Qt::AlignCenter);

Expand Down Expand Up @@ -361,6 +361,7 @@ void MainWindowInputQSO::clear()
rxPowerSpinBox->setValue(0);
if (!keepCommentCheckBox->isChecked())
commentLineEdit->clear();
setNewGrid(false);
modify = false;
fillingQSO = false;
}
Expand Down Expand Up @@ -395,6 +396,25 @@ void MainWindowInputQSO::clearDXLocator()
//qDebug() << Q_FUNC_INFO << " - Start";
locatorLineEdit->clear ();
completedWithPreviousLocator = false;
setNewGrid(false);
}

void MainWindowInputQSO::setNewGrid(const bool _new, const QString &_text)
{
//qDebug() << Q_FUNC_INFO << " - " << _new << _text;
// While a new grid is being entered, the DX Locator label turns into a red
// "New Locator..." (text supplied by the caller, which knows the band/prop)
// until the QSO is saved (or the grid is no longer new).
if (_new)
{
locLabel->setText(_text);
locLabel->setStyleSheet("QLabel { color : red; font-weight : bold; }");
}
else
{
locLabel->setText(tr("DX Locator"));
locLabel->setStyleSheet(QString());
}
}

void MainWindowInputQSO::slotReturnPressed()
Expand Down
2 changes: 2 additions & 0 deletions src/inputwidgets/mainwindowinputqso.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class MainWindowInputQSO : public QWidget

QString getDXLocator();
void setDXLocator(const QString &_loc, bool _completing = false);
void setNewGrid(const bool _new, const QString &_text = QString()); // Turns the DX Locator label into a red "New Locator..." when the grid is new

QString getName();
void setName(const QString &_st, bool _completing = false);
Expand Down Expand Up @@ -126,6 +127,7 @@ private slots:

QLineEdit *rstTXLineEdit, *rstRXLineEdit, *qthLineEdit, *locatorLineEdit, *nameLineEdit;
QLineEdit *commentLineEdit;
QLabel *locLabel; // DX Locator label; turns into a red "New Locator" when the grid is new
QDoubleSpinBox *rxPowerSpinBox, *txFreqSpinBox, *rxFreqSpinBox;
QCheckBox *splitCheckBox;
QCheckBox *keepCommentCheckBox;
Expand Down
32 changes: 32 additions & 0 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@
_entityStatus.status = awards.getQSOStatus(_entityStatus.dxcc, _entityStatus.bandId, manageMode ? _entityStatus.modeId : -1);
showStatusOfDXCC(_entityStatus);
}
checkNewGrid();
changingBand = false;
logEvent(Q_FUNC_INFO, "END", Debug);
//qDebug() << "MainWindow::slotBandChanged: END" ;
Expand Down Expand Up @@ -4788,6 +4789,35 @@
{
infoWidget->showDistanceAndBearing(myDataTabWidget->getMyLocator(), _loc);
}
checkNewGrid();
logEvent(Q_FUNC_INFO, "END", Debug);
}

void MainWindow::checkNewGrid()
{
logEvent(Q_FUNC_INFO, "Start", Devel);
const QString loc = QSOTabWidget->getDXLocator();
Locator locator;
if (!locator.isValidLocator(loc) || loc.length() < 4)

Check warning on line 4801 in src/mainwindow.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the init-statement to declare "locator" inside the if statement.

See more on https://sonarcloud.io/project/issues?id=ea4k_klog&issues=AZ8P7vwVxRTRgvXs-z0J&open=AZ8P7vwVxRTRgvXs-z0J&pullRequest=1036
{
QSOTabWidget->setNewGrid(false);
logEvent(Q_FUNC_INFO, "END-1", Debug);
return;
}
const QString bandName = mainQSOEntryWidget->getBand();
const int bandId = dataProxy->getIdFromBandName(bandName);
const QString grid4 = loc.left(4).toUpper();
// Satellite QSOs are tracked apart from terrestrial bands.
const QString prop = othersTabWidget->getPropModeFromComboBox();
const bool isSat = (prop.trimmed().toUpper() == "SAT");
// When editing a QSO, exclude it from the count so its own grid does not mask a "new" status.
const int excludeId = modify ? modifyingQSOid : -1;
const bool isNew = dataProxy->isNewGridOnBand(grid4, bandId, currentLog, prop, excludeId);
if (isNew)

Check warning on line 4816 in src/mainwindow.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the init-statement to declare "isNew" inside the if statement.

See more on https://sonarcloud.io/project/issues?id=ea4k_klog&issues=AZ8zMpdTPgOMskWIq7p2&open=AZ8zMpdTPgOMskWIq7p2&pullRequest=1036
QSOTabWidget->setNewGrid(true, isSat ? tr("New Locator on Sats")
: tr("New Locator on %1 Band").arg(bandName));
else
QSOTabWidget->setNewGrid(false);
logEvent(Q_FUNC_INFO, "END", Debug);
}

Expand Down Expand Up @@ -5515,6 +5545,7 @@

othersTabWidget->setPropMode(_p, _keep);
QSOTabWidget->setPropModeFromSat(_p);
checkNewGrid();
logEvent(Q_FUNC_INFO, "END", Debug);
//int indexC = propModeComboBox->findText(" - " + _p + " - ", Qt::MatchContains);
//propModeComboBox->setCurrentIndex(indexC);
Expand All @@ -5528,6 +5559,7 @@
//qDebug() << Q_FUNC_INFO << ": Is NOT SAT propagation mode";
satTabWidget->setNoSat();
}
checkNewGrid();
}

void MainWindow::clearIfNotCompleted()
Expand Down
1 change: 1 addition & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ private slots:
//bool checkContest();
void showStatusOfDXCC(EntityStatus _entityStatus);
void showDXMarathonNeeded(const int _dxcc, const int _cqz, const int _year, const int _log);
void checkNewGrid(); // Updates the QSO tab "New Locator" label depending on the DX locator, band and prop mode

bool createConnection();
void openSetup(const int _page=0);
Expand Down
Loading