diff --git a/src/dataproxy_sqlite.cpp b/src/dataproxy_sqlite.cpp index 49095368..9259b1ea 100644 --- a/src/dataproxy_sqlite.cpp +++ b/src/dataproxy_sqlite.cpp @@ -7800,6 +7800,87 @@ QStringList DataProxy_SQLite::getSpecialCallsigns() return qs; } +QList DataProxy_SQLite::getSpecialCallsignPairs() +{ + QList result; + QSqlQuery query; + query.setForwardOnly(true); + if (query.exec("SELECT substr(prefix, 2), dxcc, cqz, ituz FROM prefixesofentity WHERE prefix LIKE '=%' ORDER BY prefix")) + { + while (query.next()) + { + SpecialCallsignInfo info; + info.callsign = query.value(0).toString(); + info.dxcc = query.value(1).toInt(); + info.cqz = query.value(2).toInt(); + info.ituz = query.value(3).toInt(); + result.append(info); + } + } + else + { + emit queryError(Q_FUNC_INFO, query.lastError().databaseText(), query.lastError().text(), query.lastQuery()); + } + return result; +} + +bool DataProxy_SQLite::addSpecialCallsign(const QString &callsign, int dxccId, int cqz, int ituz) +{ + // If a zone is not provided (< 1), fall back to the entity's default + if (cqz < 1) cqz = getCQzFromEntity(dxccId); + if (ituz < 1) ituz = getITUzFromEntity(dxccId); + if (cqz < 0 || ituz < 0) + return false; + + const QString prefix = "=" + callsign.toUpper(); + QSqlQuery query; + query.prepare("INSERT OR REPLACE INTO prefixesofentity (prefix, dxcc, cqz, ituz) VALUES (?, ?, ?, ?)"); + query.addBindValue(prefix); + query.addBindValue(dxccId); + query.addBindValue(cqz); + query.addBindValue(ituz); + if (!query.exec()) + { + emit queryError(Q_FUNC_INFO, query.lastError().databaseText(), query.lastError().text(), query.lastQuery()); + return false; + } + return true; +} + +bool DataProxy_SQLite::removeSpecialCallsign(const QString &callsign) +{ + const QString prefix = "=" + callsign.toUpper(); + QSqlQuery query; + query.prepare("DELETE FROM prefixesofentity WHERE prefix = ?"); + query.addBindValue(prefix); + if (!query.exec()) + { + emit queryError(Q_FUNC_INFO, query.lastError().databaseText(), query.lastError().text(), query.lastQuery()); + return false; + } + return query.numRowsAffected() > 0; +} + +int DataProxy_SQLite::getKLogSubEntityForCallsign(const QString &callsign, int baseDxcc) +{ + // Inverse of the +1000 loop in World::readCTYCSV(): given the ARRL DXCC + // (e.g. 248 for Italy), find the longest prefix in prefixesofentity whose + // dxcc is a KLog sub-entity (>= 1000 and % 1000 == baseDxcc) and which the + // callsign begins with. Returns 0 if no sub-entity applies. + if (callsign.isEmpty() || baseDxcc <= 0 || baseDxcc >= 1000) + return 0; + QSqlQuery q; + q.prepare("SELECT dxcc FROM prefixesofentity " + "WHERE dxcc >= 1000 AND dxcc % 1000 = :base " + "AND :call LIKE prefix || '%' " + "ORDER BY length(prefix) DESC LIMIT 1"); + q.bindValue(":base", baseDxcc); + q.bindValue(":call", callsign.toUpper()); + if (q.exec() && q.next()) + return q.value(0).toInt(); + return 0; +} + /* bool DataProxy_SQLite::getFreqHashData() { @@ -8345,6 +8426,15 @@ QString DataProxy_SQLite::getADIFFromQSOQuery(QSqlRecord rec, ExportMode _em, bo qso.setDXCC((getADIFValueFromRec(rec, "dxcc")).toInt()); //qDebug() << Q_FUNC_INFO << ": - 100"; + // For QSOs stored with the base DXCC (e.g. 248 for Italy), check whether + // the callsign prefix maps to a KLog sub-entity (e.g. 1248 for Sicily) + // so that APP_KLOG_DXCC can be emitted on export. + { + int sub = getKLogSubEntityForCallsign(qso.getCall(), qso.getDXCC()); + if (sub > 0) + qso.setKlogDxcc(sub); + } + qso.setAddress(getADIFValueFromRec(rec, "address")); qso.setAge((getADIFValueFromRec(rec, "age")).toDouble()); diff --git a/src/dataproxy_sqlite.h b/src/dataproxy_sqlite.h index 33e64aa0..3346a0a6 100644 --- a/src/dataproxy_sqlite.h +++ b/src/dataproxy_sqlite.h @@ -255,6 +255,20 @@ class DataProxy_SQLite : public QObject QString getEntityPrefixes(const int _enti); QStringList getLongPrefixes(); QStringList getSpecialCallsigns(); + + struct SpecialCallsignInfo { + QString callsign; + int dxcc; + int cqz; + int ituz; + }; + QList getSpecialCallsignPairs(); + bool addSpecialCallsign(const QString &callsign, int dxccId, int cqz = -1, int ituz = -1); + bool removeSpecialCallsign(const QString &callsign); + // Mirror of the +1000 logic in World::readCTYCSV(): given a callsign and its + // base ARRL DXCC, look up prefixesofentity to find the KLog sub-entity + // (id >= 1000 whose id % 1000 matches the base). Returns 0 if none found. + int getKLogSubEntityForCallsign(const QString &callsign, int baseDxcc); QHash getWorldData(); //bool getFreqHashData(); diff --git a/src/filemanager.cpp b/src/filemanager.cpp index d24a292e..8b8307fb 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -996,6 +996,15 @@ int FileManager::processQSO(QSO& qso, const QString& _stationCallsign) if (qso.getDXCC() < 1) qso.setDXCC(world->getQRZARRLId(qso.getCall())); + // Restore KLog sub-entity (e.g. 1248 for Sicily) from APP_KLOG_DXCC if the + // value is consistent with the standard DXCC and matches the callsign prefix. + { + int kd = qso.getKlogDxcc(); + int d = qso.getDXCC(); + if (kd >= 1000 && d > 0 && kd % 1000 == d && world->getQRZARRLId(qso.getCall()) == kd) + qso.setDXCC(kd); + } + // 4. LoTW path: quirurgical UPDATE of only LoTW fields, no full SELECT+UPDATE if (qso.getLoTWUpdating()) { diff --git a/src/inputwidgets/mainwindowinputothers.cpp b/src/inputwidgets/mainwindowinputothers.cpp index 9f25293a..3c55bab2 100644 --- a/src/inputwidgets/mainwindowinputothers.cpp +++ b/src/inputwidgets/mainwindowinputothers.cpp @@ -79,7 +79,7 @@ QSO MainWindowInputOthers::getQSOData(QSO _qso) { QSO qso = _qso; - qso.setDXCC(getEntity() % 1000); + qso.setDXCC(getEntity()); //qDebug() << Q_FUNC_INFO << " - DXCC: " << qso.getDXCC(); qso.setState(getState()); // qso.setCounty() //TODO: Related to entitySecDivComboBox when implemented diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 01762774..b0262d3c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5623,11 +5623,8 @@ void MainWindow::slotShowQSOsFromDXCCWidget(QList _qsos) //qDebug() << Q_FUNC_INFO << "Call: " << q.getCall(); //qDebug() << Q_FUNC_INFO << "Mode: " << q.getMode(); - int dxcc = world->getQRZARRLId(q.getCall()); - //qDebug() << Q_FUNC_INFO << "040"; - dxcc = util->getNormalizedDXCCValue (dxcc); + q.setDXCC(world->getQRZARRLId(q.getCall())); //qDebug() << Q_FUNC_INFO << "050"; - q.setDXCC(dxcc); q.setClubLogStatus(clublogSentDefault); q.setLoTWQSL_SENT(lotwSentDefault); q.setEQSLQSL_SENT(eqslSentDefault); diff --git a/src/qso.cpp b/src/qso.cpp index 38c86fd9..83ac5d77 100644 --- a/src/qso.cpp +++ b/src/qso.cpp @@ -98,6 +98,7 @@ QSO::QSO(const QSO &other) darc_dok = other.darc_dok; distance = other.distance; dxcc = other.dxcc; + klogDxcc = other.klogDxcc; email = other.email; ownerCall = other.ownerCall; contacted_owner = other.contacted_owner; @@ -234,6 +235,7 @@ void QSO::operator=(QSO const &_other) qsoId = _other.qsoId; logId = _other.logId; dxcc = _other.dxcc; + klogDxcc = _other.klogDxcc; a_index = _other.a_index; k_index = _other.k_index; cqz = _other.cqz; @@ -446,6 +448,7 @@ bool QSO::copy(const QSO& other) setDarcDok(other.darc_dok); setDistance(other.distance); setDXCC(other.dxcc); + klogDxcc = other.klogDxcc; setEmail(other.email); setOwnerCallsign(other.ownerCall); setContactedOperator(other.contacted_op); @@ -672,6 +675,7 @@ void QSO::clear() darc_dok = QString(); distance = -1.0; dxcc = 0; + klogDxcc = 0; email = QString(); ownerCall = QString(); contacted_owner = QString(); @@ -1761,6 +1765,23 @@ int QSO::getDXCC() const return dxcc; } +bool QSO::setKlogDxcc(const int _i) +{ + if (_i >= 1000 && _i % 1000 > 0) + klogDxcc = _i; + return true; +} + +bool QSO::setKlogDxcc(const QString &data) +{ + return setKlogDxcc(data.toInt()); +} + +int QSO::getKlogDxcc() const +{ + return klogDxcc; +} + bool QSO::setPropMode(const QString &_c) { //qDebug() << Q_FUNC_INFO << _c; @@ -3580,6 +3601,7 @@ void QSO::InitializeHash() { {"DARC_DOK", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setDarcDok)}, {"DISTANCE", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setDistance)}, {"DXCC", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setDXCC)}, + {"APP_KLOG_DXCC", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setKlogDxcc)}, {"EMAIL", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setEmail)}, {"EQ_CALL", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setOwnerCallsign)}, {"EQSL_QSLRDATE", decltype(std::mem_fn(&QSO::decltype_function))(&QSO::setEQSLQSLRDate)}, @@ -3913,8 +3935,14 @@ QString QSO::getADIFStandard() if (adif->isValidITUz(itu_zone)) adifStr.append(adif->getADIFField ("ITUZ", QString::number(itu_zone) )); - if (adif->isValidDXCC(dxcc) && (dxcc>0)) - adifStr.append(adif->getADIFField ("DXCC", QString::number(dxcc))); + { + int adifDxcc = (dxcc >= 1000) ? (dxcc % 1000) : dxcc; + int klogExport = (dxcc >= 1000) ? dxcc : klogDxcc; + if (adif->isValidDXCC(adifDxcc) && adifDxcc > 0) + adifStr.append(adif->getADIFField("DXCC", QString::number(adifDxcc))); + if (klogExport >= 1000) + adifStr.append(adif->getADIFField("APP_KLOG_DXCC", QString::number(klogExport))); + } adifStr.append(adif->getADIFField ("ADDRESS", address)); if (age>0.0) //Only relevant if Age >0 adifStr.append(adif->getADIFField ("AGE", QString::number(age))); @@ -4209,8 +4237,14 @@ QString QSO::getADIFClubLog() //Utilities util(Q_FUNC_INFO); adifStr.append(adif->getADIFField ("QSO_DATE", util->getADIFDateFromQDateTime(qso_dateTime))); adifStr.append(adif->getADIFField ("TIME_ON", util->getADIFTimeFromQDateTime(qso_dateTime))); - if (adif->isValidDXCC(dxcc) && (dxcc>0)) - adifStr.append(adif->getADIFField ("DXCC", QString::number(dxcc))); + { + int adifDxcc = (dxcc >= 1000) ? (dxcc % 1000) : dxcc; + int klogExport = (dxcc >= 1000) ? dxcc : klogDxcc; + if (adif->isValidDXCC(adifDxcc) && adifDxcc > 0) + adifStr.append(adif->getADIFField("DXCC", QString::number(adifDxcc))); + if (klogExport >= 1000) + adifStr.append(adif->getADIFField("APP_KLOG_DXCC", QString::number(klogExport))); + } adifStr.append(adif->getADIFField ("credit_granted", credit_granted )); adifStr.append(adif->getADIFField ("lotw_qsl_rcvd", lotw_qsl_rcvd)); adifStr.append(adif->getADIFField ("qsl_rcvd", getQSL_RCVD())); diff --git a/src/qso.h b/src/qso.h index 1db482b6..edd85f7f 100644 --- a/src/qso.h +++ b/src/qso.h @@ -173,6 +173,9 @@ class QSO : public QObject // Others Tab bool setDXCC(const int _i); int getDXCC() const; + bool setKlogDxcc(const int _i); + bool setKlogDxcc(const QString &data); + int getKlogDxcc() const; bool setPropMode(const QString &_c); QString getPropMode() const; bool setSOTA_REF(const QString &_c); @@ -498,7 +501,7 @@ class QSO : public QObject void logEvent(const QString &_func, const QString &_msg, DebugLogLevel _level); void cleanMode(); // Cleans mode & submode - int qsoId, logId, dxcc, k_index, cqz, fists, fists_cc, my_fists, iota_ID, itu_zone, nr_bursts, max_bursts, nr_pings, my_cqz, my_itu_zone, my_dxcc, my_iota_ID, srx, stx, uksmg; + int qsoId, logId, dxcc, klogDxcc, k_index, cqz, fists, fists_cc, my_fists, iota_ID, itu_zone, nr_bursts, max_bursts, nr_pings, my_cqz, my_itu_zone, my_dxcc, my_iota_ID, srx, stx, uksmg; int ten_ten, sfi; double pwr_rx, pwr_tx, age, ant_el, ant_az, distance, altitude, my_altitude, a_index; Frequency freq_tx, freq_rx; diff --git a/src/setuppages/setuppageworldeditor.cpp b/src/setuppages/setuppageworldeditor.cpp index 8d916197..2e66842a 100644 --- a/src/setuppages/setuppageworldeditor.cpp +++ b/src/setuppages/setuppageworldeditor.cpp @@ -25,6 +25,87 @@ *****************************************************************************/ #include "setuppageworldeditor.h" +#include "../callsign.h" + +// --------------------------------------------------------------------------- +// AddSpecialCallsignDialog implementation +// --------------------------------------------------------------------------- + +AddSpecialCallsignDialog::AddSpecialCallsignDialog(World *w, QWidget *parent) + : QDialog(parent), world(w) +{ + setWindowTitle(tr("Add Special Callsign")); + + callLineEdit = new QLineEdit(this); + callLineEdit->setPlaceholderText(tr("e.g. RI1ANY")); + + entityCombo = new QComboBox(this); + { + QSqlQuery q; + q.setForwardOnly(true); + if (q.exec("SELECT name, dxcc FROM entity WHERE (deleted IS NULL OR deleted=0) ORDER BY name")) + { + while (q.next()) + entityCombo->addItem(q.value(0).toString(), q.value(1).toInt()); + } + } + + cqzCheck = new QCheckBox(tr("Override CQ Zone:"), this); + cqzSpin = new QSpinBox(this); + cqzSpin->setRange(1, 40); + cqzSpin->setEnabled(false); + connect(cqzCheck, &QCheckBox::toggled, cqzSpin, &QSpinBox::setEnabled); + + ituzCheck = new QCheckBox(tr("Override ITU Zone:"), this); + ituzSpin = new QSpinBox(this); + ituzSpin->setRange(1, 90); + ituzSpin->setEnabled(false); + connect(ituzCheck, &QCheckBox::toggled, ituzSpin, &QSpinBox::setEnabled); + + // Proper slot — fires every time the entity combo changes + connect(entityCombo, QOverload::of(&QComboBox::currentIndexChanged), + this, &AddSpecialCallsignDialog::slotEntityChanged); + + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + auto *cqzRow = new QHBoxLayout; + cqzRow->addWidget(cqzCheck); + cqzRow->addWidget(cqzSpin); + cqzRow->addStretch(); + + auto *ituzRow = new QHBoxLayout; + ituzRow->addWidget(ituzCheck); + ituzRow->addWidget(ituzSpin); + ituzRow->addStretch(); + + auto *form = new QFormLayout; + form->addRow(tr("Callsign:"), callLineEdit); + form->addRow(tr("Entity:"), entityCombo); + form->addRow(cqzRow); + form->addRow(ituzRow); + form->addRow(buttonBox); + + setLayout(form); + + // Populate zone spinboxes with the first entity's defaults + slotEntityChanged(0); +} + +void AddSpecialCallsignDialog::slotEntityChanged(int /*index*/) +{ + const int dxcc = entityCombo->currentData().toInt(); + const int cq = world->getEntityCqz(dxcc); + const int itu = world->getEntityItuz(dxcc); + if (cq > 0) cqzSpin->setValue(cq); + if (itu > 0) ituzSpin->setValue(itu); +} + +QString AddSpecialCallsignDialog::callsign() const { return callLineEdit->text().toUpper().trimmed(); } +int AddSpecialCallsignDialog::selectedDxcc() const { return entityCombo->currentData().toInt(); } +int AddSpecialCallsignDialog::cqz() const { return cqzCheck->isChecked() ? cqzSpin->value() : -1; } +int AddSpecialCallsignDialog::ituz() const { return ituzCheck->isChecked() ? ituzSpin->value() : -1; } SetupPageWorldEditor::SetupPageWorldEditor(DataProxy_SQLite *dp, World *injectedWorld, QWidget *parent) : QWidget(parent) { @@ -88,10 +169,13 @@ SetupPageWorldEditor::SetupPageWorldEditor(DataProxy_SQLite *dp, World *injected buttonsLayout->addWidget(editEntityPushButton); buttonsLayout->addWidget(delEntityPushButton); + createSpecialCallsignsPanel(); + QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(worldView); layout->addLayout(buttonsLayout); + layout->addWidget(specialCallsignsGroup); //qDebug() << Q_FUNC_INFO << " - 50"; setLayout(layout); @@ -245,6 +329,9 @@ void SetupPageWorldEditor::createActions() connect(loadWorldPushButton, SIGNAL(clicked()), this, SLOT(slotImportWorldButtonClicked()) ); + connect(addSpecialButton, &QPushButton::clicked, this, &SetupPageWorldEditor::slotAddSpecialCallsignClicked); + connect(removeSpecialButton, &QPushButton::clicked, this, &SetupPageWorldEditor::slotRemoveSpecialCallsignClicked); + @@ -344,7 +431,114 @@ void SetupPageWorldEditor::slotImportWorldButtonClicked() msgBox.setText(tr("Entities information has not been updated.")); } msgBox.exec(); + refreshSpecialCallsignsTable(); //qDebug() << "SetupPageWorldEditor::slotImportWorldButtonClicked - END"; } +void SetupPageWorldEditor::createSpecialCallsignsPanel() +{ + specialCallsignsGroup = new QGroupBox(tr("Special Callsigns")); + specialCallsignsGroup->setToolTip(tr("Callsigns not in the CTY data that should map to a specific DXCC entity (e.g. expedition callsigns like RI1ANY for Antarctica).")); + + specialCallsignsTable = new QTableWidget(0, 4, specialCallsignsGroup); + specialCallsignsTable->setHorizontalHeaderLabels({tr("Callsign"), tr("Entity"), tr("CQ Zone"), tr("ITU Zone")}); + specialCallsignsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + specialCallsignsTable->setSelectionMode(QAbstractItemView::SingleSelection); + specialCallsignsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + specialCallsignsTable->horizontalHeader()->setStretchLastSection(true); + specialCallsignsTable->verticalHeader()->setVisible(false); + + addSpecialButton = new QPushButton(tr("Add")); + removeSpecialButton = new QPushButton(tr("Remove")); + removeSpecialButton->setEnabled(false); + + connect(specialCallsignsTable, &QTableWidget::itemSelectionChanged, this, [this]() { + removeSpecialButton->setEnabled(!specialCallsignsTable->selectedItems().isEmpty()); + }); + + QHBoxLayout *btnLayout = new QHBoxLayout; + btnLayout->addStretch(); + btnLayout->addWidget(addSpecialButton); + btnLayout->addWidget(removeSpecialButton); + + QVBoxLayout *groupLayout = new QVBoxLayout; + groupLayout->addWidget(specialCallsignsTable); + groupLayout->addLayout(btnLayout); + specialCallsignsGroup->setLayout(groupLayout); + + refreshSpecialCallsignsTable(); +} + +void SetupPageWorldEditor::refreshSpecialCallsignsTable() +{ + specialCallsignsTable->setRowCount(0); + const auto entries = dataProxy->getSpecialCallsignPairs(); + for (const auto &e : entries) + { + const int row = specialCallsignsTable->rowCount(); + specialCallsignsTable->insertRow(row); + specialCallsignsTable->setItem(row, 0, new QTableWidgetItem(e.callsign)); + specialCallsignsTable->setItem(row, 1, new QTableWidgetItem(world->getEntityName(e.dxcc))); + specialCallsignsTable->setItem(row, 2, new QTableWidgetItem(QString::number(e.cqz))); + specialCallsignsTable->setItem(row, 3, new QTableWidgetItem(QString::number(e.ituz))); + } + specialCallsignsTable->resizeColumnToContents(0); + specialCallsignsTable->resizeColumnToContents(2); + specialCallsignsTable->resizeColumnToContents(3); + removeSpecialButton->setEnabled(false); +} + +void SetupPageWorldEditor::slotAddSpecialCallsignClicked() +{ + AddSpecialCallsignDialog dlg(world, this); + if (dlg.exec() != QDialog::Accepted) + return; + + const QString call = dlg.callsign(); + if (call.isEmpty()) + return; + + Callsign cs(call); + if (!cs.isValid()) + { + QMessageBox::warning(this, tr("Invalid Callsign"), + tr("'%1' is not a valid callsign.").arg(call)); + return; + } + + if (!dataProxy->addSpecialCallsign(call, dlg.selectedDxcc(), dlg.cqz(), dlg.ituz())) + { + QMessageBox::warning(this, tr("Error"), + tr("Could not add the special callsign. It may already exist.")); + return; + } + + world->readWorld(); + refreshSpecialCallsignsTable(); +} + +void SetupPageWorldEditor::slotRemoveSpecialCallsignClicked() +{ + const int row = specialCallsignsTable->currentRow(); + if (row < 0) + return; + + const QString call = specialCallsignsTable->item(row, 0)->text(); + const int ret = QMessageBox::question(this, tr("Remove Special Callsign"), + tr("Remove '%1' from the special callsigns list?").arg(call)); + if (ret != QMessageBox::Yes) + return; + + if (dataProxy->removeSpecialCallsign(call)) + { + world->readWorld(); + refreshSpecialCallsignsTable(); + } + else + { + QMessageBox::warning(this, tr("Error"), + tr("Could not remove the special callsign '%1'.").arg(call)); + } +} + diff --git a/src/setuppages/setuppageworldeditor.h b/src/setuppages/setuppageworldeditor.h index 6de7ad78..53770e49 100644 --- a/src/setuppages/setuppageworldeditor.h +++ b/src/setuppages/setuppageworldeditor.h @@ -46,6 +46,30 @@ enum WORLD_Cont = 5 }; +// --------------------------------------------------------------------------- +// Dialog for adding a special callsign override +// --------------------------------------------------------------------------- +class AddSpecialCallsignDialog : public QDialog { + Q_OBJECT +public: + explicit AddSpecialCallsignDialog(World *w, QWidget *parent = nullptr); + + QString callsign() const; + int selectedDxcc() const; + int cqz() const; // -1 = use entity default + int ituz() const; // -1 = use entity default + +private slots: + void slotEntityChanged(int index); + +private: + World *world; + QLineEdit *callLineEdit; + QComboBox *entityCombo; + QCheckBox *cqzCheck, *ituzCheck; + QSpinBox *cqzSpin, *ituzSpin; +}; + class SetupPageWorldEditor : public QWidget { Q_OBJECT @@ -61,6 +85,8 @@ private slots: void slotAnalyzeEntityAddedSignal(const QStringList _qs); void slotImportWorldButtonClicked(); + void slotAddSpecialCallsignClicked(); + void slotRemoveSpecialCallsignClicked(); private: World *world; @@ -71,12 +97,17 @@ private slots: void createWorldModel(); void createActions(); bool isWorldEmpty(); + void createSpecialCallsignsPanel(); + void refreshSpecialCallsignsTable(); QSqlRelationalTableModel *worldModel; QWidget *worldPanel; QTableView *worldView; QTreeWidget *searchResultsTreeWidget; + QGroupBox *specialCallsignsGroup; + QTableWidget *specialCallsignsTable; + QPushButton *addSpecialButton, *removeSpecialButton; QPushButton *addEntityPushButton, *delEntityPushButton, *editEntityPushButton, *exportWorldPushButton, *loadWorldPushButton; diff --git a/src/utilities.cpp b/src/utilities.cpp index e937b2ed..d79f3484 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -1214,8 +1214,14 @@ bool Utilities::isValidDateTimeFromString(const QString &_s) } bool Utilities::isValidDXCC(const int _d) -{//TODO: Look for a better way to check, taking into account how KLog is identifiying the DXCC - return (((_d > 0) && (_d < 523)) || (_d == 1206) || (_d == 1279) || (_d == 1248) || (_d == 2248) || (_d == 1259) || (_d == 1390)); +{ + if (_d <= 0) + return false; + if (_d < 523) + return true; + // KLog special entities: base DXCC + i*1000 (i >= 1) + int base = _d % 1000; + return (base > 0 && base < 523); } bool Utilities::isValidAntPath(const QString &_s) diff --git a/src/world.cpp b/src/world.cpp index 41cfde14..133a9b09 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -443,11 +443,11 @@ int World::selectEntity(const int _ent1, const int _ent2) if (_ent1 == _ent2 && _ent1 > 0) return _ent1; - // Case I(248) vs IT9(2248) + // Case I(248) vs IT9(1248): prefer the more specific sub-entity int higher = std::max(_ent1, _ent2); int lower = std::min(_ent1, _ent2); if (higher % 1000 == lower) - return lower; + return higher; return -1; } diff --git a/src/world.h b/src/world.h index f5a1fcee..1bbc1d15 100644 --- a/src/world.h +++ b/src/world.h @@ -87,7 +87,7 @@ class World : public QObject double getLongitude(const int _enti); // Returns the longitude of the Entity double getLatitude(const int _enti); // Returns the latitude of the Entity - int selectEntity(const int _ent1, const int _ent2); // Useful to return Italy 248 if 248 or 2248 (IT9) are delivered. -1 if no selection can be made + int selectEntity(const int _ent1, const int _ent2); // Returns the more specific sub-entity (e.g. 1248 over 248) or -1 if unrelated int getEntityCqz(const int _enti); int getQRZCqz(const QString &_qrz); //int getPrefixCQz(const QString &_p);