2018-02-08 21:28:33 -05:00
|
|
|
#include "logqso.h"
|
|
|
|
|
|
|
|
#include <QString>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QStandardPaths>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QDebug>
|
2018-03-05 14:49:51 -05:00
|
|
|
#include <QUdpSocket>
|
2018-02-08 21:28:33 -05:00
|
|
|
|
|
|
|
#include "logbook/adif.h"
|
|
|
|
#include "MessageBox.hpp"
|
|
|
|
#include "Configuration.hpp"
|
|
|
|
#include "Bands.hpp"
|
2018-08-05 11:33:30 -04:00
|
|
|
#include "MaidenheadLocatorValidator.hpp"
|
2019-06-01 10:43:03 -04:00
|
|
|
#include "DriftingDateTime.h"
|
2018-02-08 21:28:33 -05:00
|
|
|
|
|
|
|
#include "ui_logqso.h"
|
|
|
|
#include "moc_logqso.cpp"
|
|
|
|
|
|
|
|
LogQSO::LogQSO(QString const& programTitle, QSettings * settings
|
|
|
|
, Configuration const * config, QWidget *parent)
|
2018-03-07 01:57:18 -05:00
|
|
|
: QDialog {parent, Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint}
|
2018-02-08 21:28:33 -05:00
|
|
|
, ui(new Ui::LogQSO)
|
|
|
|
, m_settings (settings)
|
|
|
|
, m_config {config}
|
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
|
|
|
setWindowTitle(programTitle + " - Log QSO");
|
2018-08-05 11:33:30 -04:00
|
|
|
ui->grid->setValidator (new MaidenheadLocatorValidator {this});
|
2018-02-08 21:28:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
LogQSO::~LogQSO ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-06-01 22:41:10 -04:00
|
|
|
bool LogQSO::acceptText(QString text){
|
|
|
|
auto w = focusWidget();
|
|
|
|
if(!w){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto name = QString(w->metaObject()->className());
|
|
|
|
if(name != "QLineEdit"){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto l = static_cast<QLineEdit*>(w);
|
2019-06-02 21:34:39 -04:00
|
|
|
if(l->text().isEmpty()){
|
|
|
|
// set
|
|
|
|
l->setText(text);
|
|
|
|
} else {
|
|
|
|
// append
|
|
|
|
l->setText(QString("%1 %2").arg(l->text()).arg(text));
|
2019-06-01 22:41:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-05 14:19:31 -04:00
|
|
|
QString LogQSO::currentCall(){
|
|
|
|
return ui->call->text().trimmed();
|
|
|
|
}
|
|
|
|
|
2019-06-01 10:43:03 -04:00
|
|
|
void LogQSO::on_start_now_button_pressed(){
|
|
|
|
ui->start_date_time->setDateTime(DriftingDateTime::currentDateTimeUtc());
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogQSO::on_end_now_button_pressed(){
|
|
|
|
ui->end_date_time->setDateTime(DriftingDateTime::currentDateTimeUtc());
|
|
|
|
}
|
|
|
|
|
2019-06-04 17:05:33 -04:00
|
|
|
void LogQSO::on_add_new_field_button_pressed(){
|
|
|
|
createAdditionalField();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogQSO::createAdditionalField(QString key, QString value){
|
|
|
|
QLineEdit * l = new QLineEdit(this);
|
|
|
|
if(!value.isEmpty()){
|
|
|
|
l->setText(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
QComboBox * c = new QComboBox(this);
|
|
|
|
c->insertItems(0, ADIF_FIELDS);
|
2019-06-05 11:35:07 -04:00
|
|
|
c->insertItem(0, "");
|
2019-06-07 14:19:37 -04:00
|
|
|
c->setEditable(true);
|
|
|
|
c->setAutoCompletion(true);
|
|
|
|
c->setAutoCompletionCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
c->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
2019-06-04 17:05:33 -04:00
|
|
|
connect(c, &QComboBox::currentTextChanged, this, [this, l](const QString &text){
|
|
|
|
l->setProperty("fieldKey", QVariant(text));
|
|
|
|
});
|
2019-06-05 11:45:19 -04:00
|
|
|
c->setCurrentText(key);
|
2019-06-04 17:05:33 -04:00
|
|
|
|
|
|
|
auto layout = static_cast<QFormLayout*>(ui->additionalFields->layout());
|
|
|
|
layout->addRow(c, l);
|
2019-06-05 11:45:19 -04:00
|
|
|
|
|
|
|
// set tab ordering
|
|
|
|
if(m_additionalFieldsControls.isEmpty()){
|
|
|
|
setTabOrder(ui->cbComments, c);
|
|
|
|
} else {
|
|
|
|
setTabOrder(m_additionalFieldsControls.last(), c);
|
|
|
|
}
|
|
|
|
setTabOrder(c, l);
|
|
|
|
setTabOrder(l, ui->add_new_field_button);
|
|
|
|
c->setFocus();
|
|
|
|
|
2019-06-04 17:05:33 -04:00
|
|
|
m_additionalFieldsControls.append(l);
|
2019-06-07 10:00:14 -04:00
|
|
|
ui->additionalFields->setVisible(true);
|
2019-06-07 14:19:37 -04:00
|
|
|
ui->additionalFields->adjustSize();
|
2019-06-04 17:05:33 -04:00
|
|
|
}
|
|
|
|
|
2019-06-05 11:33:21 -04:00
|
|
|
QMap<QString, QVariant> LogQSO::collectAdditionalFields(){
|
|
|
|
QMap<QString, QVariant> additionalFields;
|
|
|
|
foreach(auto field, m_additionalFieldsControls){
|
|
|
|
auto key = field->property("fieldKey").toString();
|
|
|
|
if(key.isEmpty()){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
additionalFields[key] = QVariant(field->text());
|
|
|
|
}
|
|
|
|
return additionalFields;
|
|
|
|
}
|
|
|
|
|
2019-06-04 17:05:33 -04:00
|
|
|
void LogQSO::resetAdditionalFields(){
|
2019-06-07 10:00:14 -04:00
|
|
|
if(!m_additionalFieldsControls.isEmpty()){
|
|
|
|
auto layout = static_cast<QFormLayout*>(ui->additionalFields->layout());
|
2019-06-06 10:13:46 -04:00
|
|
|
|
|
|
|
#if QT_VERSION >= 0x050800
|
2019-06-07 10:00:14 -04:00
|
|
|
for(int i = 0, count = layout->rowCount(); i < count; i++){
|
|
|
|
layout->removeRow(0);
|
|
|
|
}
|
2019-06-06 10:13:46 -04:00
|
|
|
#else
|
2019-06-07 10:00:14 -04:00
|
|
|
QLayoutItem *child;
|
|
|
|
while((child = layout->takeAt(0)) != 0){
|
|
|
|
delete child;
|
|
|
|
}
|
2019-06-06 10:13:46 -04:00
|
|
|
#endif
|
|
|
|
|
2019-06-07 10:00:14 -04:00
|
|
|
m_additionalFieldsControls.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
setTabOrder(ui->cbComments, ui->add_new_field_button);
|
|
|
|
ui->additionalFields->setVisible(false);
|
2019-06-04 17:05:33 -04:00
|
|
|
}
|
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
void LogQSO::loadSettings ()
|
|
|
|
{
|
|
|
|
m_settings->beginGroup ("LogQSO");
|
|
|
|
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
|
|
|
|
ui->cbComments->setChecked (m_settings->value ("SaveComments", false).toBool ());
|
|
|
|
m_comments = m_settings->value ("LogComments", "").toString();
|
2019-06-04 17:05:33 -04:00
|
|
|
|
|
|
|
resetAdditionalFields();
|
2019-06-04 22:19:51 -04:00
|
|
|
auto additionalFields = m_settings->value("AdditionalFields", {}).toStringList();
|
|
|
|
QSet<QString> additionalFieldsSet;
|
2019-06-04 17:05:33 -04:00
|
|
|
foreach(auto key, additionalFields){
|
2019-06-04 22:19:51 -04:00
|
|
|
if(key.isEmpty()){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(additionalFieldsSet.contains(key)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-04 17:05:33 -04:00
|
|
|
createAdditionalField(key);
|
2019-06-04 22:19:51 -04:00
|
|
|
additionalFieldsSet.insert(key);
|
2019-06-04 17:05:33 -04:00
|
|
|
}
|
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
m_settings->endGroup ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogQSO::storeSettings () const
|
|
|
|
{
|
|
|
|
m_settings->beginGroup ("LogQSO");
|
|
|
|
m_settings->setValue ("geometry", saveGeometry ());
|
|
|
|
m_settings->setValue ("SaveComments", ui->cbComments->isChecked ());
|
|
|
|
m_settings->setValue ("LogComments", m_comments);
|
2019-06-04 17:05:33 -04:00
|
|
|
|
|
|
|
auto additionalFields = QStringList{};
|
|
|
|
foreach(auto field, m_additionalFieldsControls){
|
2019-06-04 22:19:51 -04:00
|
|
|
auto key = field->property("fieldKey").toString();
|
|
|
|
if(key.isEmpty()){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
additionalFields.append(key);
|
2019-06-04 17:05:33 -04:00
|
|
|
}
|
|
|
|
m_settings->setValue ("AdditionalFields", additionalFields);
|
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
m_settings->endGroup ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode,
|
|
|
|
QString const& rptSent, QString const& rptRcvd,
|
|
|
|
QDateTime const& dateTimeOn, QDateTime const& dateTimeOff,
|
|
|
|
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
|
2019-05-31 15:15:45 -04:00
|
|
|
bool toDATA, bool dBtoComments, bool bFox, QString const& opCall, QString const& comments)
|
2018-02-08 21:28:33 -05:00
|
|
|
{
|
|
|
|
if(!isHidden()) return;
|
2019-06-04 17:05:33 -04:00
|
|
|
|
|
|
|
loadSettings();
|
|
|
|
|
2019-06-02 13:25:31 -04:00
|
|
|
ui->call->setFocus();
|
2018-02-08 21:28:33 -05:00
|
|
|
ui->call->setText(hisCall);
|
|
|
|
ui->grid->setText(hisGrid);
|
|
|
|
ui->name->setText("");
|
|
|
|
ui->comments->setText("");
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
if (ui->cbComments->isChecked ()) ui->comments->setText(m_comments);
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
if(dBtoComments) {
|
|
|
|
QString t=mode;
|
|
|
|
if(rptSent!="") t+=" Sent: " + rptSent;
|
|
|
|
if(rptRcvd!="") t+=" Rcvd: " + rptRcvd;
|
|
|
|
ui->comments->setText(t);
|
|
|
|
}
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2019-05-31 15:15:45 -04:00
|
|
|
if(!comments.isEmpty()){
|
|
|
|
ui->comments->setText(comments);
|
|
|
|
}
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2019-02-10 09:37:26 -05:00
|
|
|
if(toDATA) mode="DATA";
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
ui->mode->setText(mode);
|
|
|
|
ui->sent->setText(rptSent);
|
|
|
|
ui->rcvd->setText(rptRcvd);
|
|
|
|
ui->start_date_time->setDateTime (dateTimeOn);
|
|
|
|
ui->end_date_time->setDateTime (dateTimeOff);
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
m_dialFreq=dialFreq;
|
|
|
|
m_myCall=myCall;
|
|
|
|
m_myGrid=myGrid;
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
ui->band->setText (m_config->bands ()->find (dialFreq));
|
2018-03-05 14:49:51 -05:00
|
|
|
ui->loggedOperator->setText(opCall);
|
2019-06-04 17:05:33 -04:00
|
|
|
|
2018-03-05 14:49:51 -05:00
|
|
|
if(bFox) {
|
|
|
|
accept();
|
|
|
|
} else {
|
|
|
|
show ();
|
|
|
|
}
|
2018-02-08 21:28:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void LogQSO::accept()
|
|
|
|
{
|
2018-11-30 17:02:14 -05:00
|
|
|
QString hisCall,hisGrid,mode,submode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band,operator_call;
|
2018-02-08 21:28:33 -05:00
|
|
|
QString comments,name;
|
|
|
|
|
2018-11-01 00:20:20 -04:00
|
|
|
hisCall=ui->call->text().toUpper();
|
|
|
|
hisGrid=ui->grid->text().toUpper();
|
2018-11-30 17:02:14 -05:00
|
|
|
mode = ui->mode->text().toUpper();
|
|
|
|
if(mode == "JS8"){
|
|
|
|
mode="MFSK";
|
|
|
|
submode="JS8";
|
|
|
|
}
|
2018-02-08 21:28:33 -05:00
|
|
|
rptSent=ui->sent->text();
|
|
|
|
rptRcvd=ui->rcvd->text();
|
|
|
|
m_dateTimeOn = ui->start_date_time->dateTime ();
|
|
|
|
m_dateTimeOff = ui->end_date_time->dateTime ();
|
|
|
|
band=ui->band->text();
|
|
|
|
name=ui->name->text();
|
|
|
|
comments=ui->comments->text();
|
|
|
|
m_comments=comments;
|
|
|
|
QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6));
|
2018-03-05 14:49:51 -05:00
|
|
|
operator_call = ui->loggedOperator->text();
|
2018-10-04 13:52:52 -04:00
|
|
|
//Log this QSO to ADIF file "js8call_log.adi"
|
|
|
|
QString filename = "js8call_log.adi"; // TODO allow user to set
|
2018-02-08 21:28:33 -05:00
|
|
|
ADIF adifile;
|
2018-11-30 17:02:14 -05:00
|
|
|
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (filename);
|
2018-02-08 21:28:33 -05:00
|
|
|
adifile.init(adifilePath);
|
2018-03-05 14:49:51 -05:00
|
|
|
|
2019-06-05 11:33:21 -04:00
|
|
|
auto additionalFields = collectAdditionalFields();
|
|
|
|
|
2018-11-30 17:02:14 -05:00
|
|
|
QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, submode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band
|
2019-06-04 22:19:51 -04:00
|
|
|
, comments, name, strDialFreq, m_myCall, m_myGrid, operator_call, additionalFields)};
|
|
|
|
|
2018-03-05 14:49:51 -05:00
|
|
|
if (!adifile.addQSOToFile (ADIF))
|
2018-02-08 21:28:33 -05:00
|
|
|
{
|
|
|
|
MessageBox::warning_message (this, tr ("Log file error"),
|
|
|
|
tr ("Cannot open \"%1\"").arg (adifilePath));
|
|
|
|
}
|
|
|
|
|
2019-06-05 11:33:21 -04:00
|
|
|
//Log this QSO to file "js8call.log"
|
2018-10-04 13:52:52 -04:00
|
|
|
static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("js8call.log")};
|
2018-02-08 21:28:33 -05:00
|
|
|
if(!f.open(QIODevice::Text | QIODevice::Append)) {
|
|
|
|
MessageBox::warning_message (this, tr ("Log file error"),
|
|
|
|
tr ("Cannot open \"%1\" for append").arg (f.fileName ()),
|
|
|
|
tr ("Error: %1").arg (f.errorString ()));
|
|
|
|
} else {
|
2019-06-05 11:33:21 -04:00
|
|
|
QStringList logEntryItems = {
|
|
|
|
m_dateTimeOn.date().toString("yyyy-MM-dd"),
|
|
|
|
m_dateTimeOn.time().toString("hh:mm:ss"),
|
|
|
|
m_dateTimeOff.date().toString("yyyy-MM-dd"),
|
|
|
|
m_dateTimeOff.time().toString("hh:mm:ss"),
|
|
|
|
hisCall,
|
|
|
|
hisGrid,
|
|
|
|
strDialFreq,
|
|
|
|
(mode == "MFSK" ? "JS8" : mode),
|
|
|
|
rptSent,
|
|
|
|
rptRcvd,
|
|
|
|
comments,
|
|
|
|
name
|
|
|
|
};
|
|
|
|
|
|
|
|
if(!additionalFields.isEmpty()){
|
|
|
|
foreach(auto value, additionalFields.values()){
|
|
|
|
logEntryItems.append(value.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
QTextStream out(&f);
|
2019-06-05 11:33:21 -04:00
|
|
|
out << logEntryItems.join(",") << endl;
|
2018-02-08 21:28:33 -05:00
|
|
|
f.close();
|
|
|
|
}
|
|
|
|
|
2019-06-05 11:33:21 -04:00
|
|
|
//Clean up and finish logging
|
2019-06-05 14:19:31 -04:00
|
|
|
ui->call->clear();
|
|
|
|
|
2019-06-05 11:33:21 -04:00
|
|
|
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, submode, rptSent, rptRcvd, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF, additionalFields);
|
|
|
|
|
2018-02-08 21:28:33 -05:00
|
|
|
QDialog::accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
// closeEvent is only called from the system menu close widget for a
|
|
|
|
// modeless dialog so we use the hideEvent override to store the
|
|
|
|
// window settings
|
|
|
|
void LogQSO::hideEvent (QHideEvent * e)
|
|
|
|
{
|
|
|
|
storeSettings ();
|
|
|
|
QDialog::hideEvent (e);
|
|
|
|
}
|