Merge branch 'release-2.1.0' of bitbucket.org:k1jt/wsjtx into release-2.1.0

This commit is contained in:
Joe Taylor 2019-06-03 08:30:09 -04:00
commit 4b51f423c2
54 changed files with 889 additions and 427 deletions

View File

@ -237,6 +237,7 @@ set (wsjt_qt_CXXSRCS
models/FrequencyList.cpp
models/StationList.cpp
widgets/FrequencyLineEdit.cpp
widgets/FrequencyDeltaLineEdit.cpp
item_delegates/CandidateKeyFilter.cpp
item_delegates/ForeignKeyDelegate.cpp
validators/LiveFrequencyValidator.cpp
@ -279,9 +280,12 @@ set (wsjt_qt_CXXSRCS
widgets/CabrilloLogWindow.cpp
item_delegates/CallsignDelegate.cpp
item_delegates/MaidenheadLocatorDelegate.cpp
item_delegates/FrequencyDelegate.cpp
item_delegates/FrequencyDeltaDelegate.cpp
models/CabrilloLog.cpp
logbook/AD1CCty.cpp
logbook/WorkedBefore.cpp
logbook/Multiplier.cpp
)
set (wsjt_qtmm_CXXSRCS

View File

@ -167,8 +167,11 @@
#include "MetaDataRegistry.hpp"
#include "SettingsGroup.hpp"
#include "widgets/FrequencyLineEdit.hpp"
#include "widgets/FrequencyDeltaLineEdit.hpp"
#include "item_delegates/CandidateKeyFilter.hpp"
#include "item_delegates/ForeignKeyDelegate.hpp"
#include "item_delegates/FrequencyDelegate.hpp"
#include "item_delegates/FrequencyDeltaDelegate.hpp"
#include "TransceiverFactory.hpp"
#include "Transceiver.hpp"
#include "models/Bands.hpp"
@ -564,6 +567,7 @@ private:
DecodeHighlightingModel decode_highlighing_model_;
DecodeHighlightingModel next_decode_highlighing_model_;
bool highlight_by_mode_;
bool include_WAE_entities_;
int LotW_days_since_upload_;
TransceiverFactory::ParameterPack rig_params_;
@ -745,6 +749,7 @@ bool Configuration::pwrBandTuneMemory () const {return m_->pwrBandTuneMemory_;}
LotWUsers const& Configuration::lotw_users () const {return m_->lotw_users_;}
DecodeHighlightingModel const& Configuration::decode_highlighting () const {return m_->decode_highlighing_model_;}
bool Configuration::highlight_by_mode () const {return m_->highlight_by_mode_;}
bool Configuration::include_WAE_entities () const {return m_->include_WAE_entities_;}
void Configuration::set_calibration (CalibrationParams params)
{
@ -950,6 +955,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
, station_insert_action_ {tr ("&Insert ..."), nullptr}
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
, highlight_by_mode_ {false}
, include_WAE_entities_ {false}
, LotW_days_since_upload_ {0}
, last_port_type_ {TransceiverFactory::Capabilities::none}
, rig_is_dummy_ {false}
@ -1119,9 +1125,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true);
// delegates
auto frequencies_item_delegate = new QStyledItemDelegate {this};
frequencies_item_delegate->setItemEditorFactory (item_editor_factory ());
ui_->frequencies_table_view->setItemDelegate (frequencies_item_delegate);
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::frequency_column, new FrequencyDelegate {this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::region_column, new ForeignKeyDelegate {&regions_, 0, this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::mode_column, new ForeignKeyDelegate {&modes_, 0, this});
@ -1160,9 +1164,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder);
// stations delegates
auto stations_item_delegate = new QStyledItemDelegate {this};
stations_item_delegate->setItemEditorFactory (item_editor_factory ());
ui_->stations_table_view->setItemDelegate (stations_item_delegate);
ui_->stations_table_view->setItemDelegateForColumn (StationList::offset_column, new FrequencyDeltaDelegate {this});
ui_->stations_table_view->setItemDelegateForColumn (StationList::band_column, new ForeignKeyDelegate {&bands_, &next_stations_, 0, StationList::band_column, this});
// stations actions
@ -1319,6 +1321,7 @@ void Configuration::impl::initialize_models ()
next_decode_highlighing_model_.items (decode_highlighing_model_.items ());
ui_->highlight_by_mode_check_box->setChecked (highlight_by_mode_);
ui_->include_WAE_check_box->setChecked (include_WAE_entities_);
ui_->LotW_days_since_upload_spin_box->setValue (LotW_days_since_upload_);
set_rig_invariants ();
@ -1467,6 +1470,7 @@ void Configuration::impl::read_settings ()
if (!highlight_items.size ()) highlight_items = DecodeHighlightingModel::default_items ();
decode_highlighing_model_.items (highlight_items);
highlight_by_mode_ = settings_->value("HighlightByMode", false).toBool ();
include_WAE_entities_ = settings_->value("IncludeWAEEntities", false).toBool ();
LotW_days_since_upload_ = settings_->value ("LotWDaysSinceLastUpload", 365).toInt ();
lotw_users_.set_age_constraint (LotW_days_since_upload_);
@ -1579,7 +1583,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
settings_->setValue ("DecodeHighlighting", QVariant::fromValue (decode_highlighing_model_.items ()));
settings_->setValue ("HighlightByMode", highlight_by_mode_);
settings_->setValue ("IncludeWAEEntities", include_WAE_entities_);
settings_->setValue ("LotWDaysSinceLastUpload", LotW_days_since_upload_);
settings_->setValue ("toRTTY", log_as_RTTY_);
settings_->setValue ("dBtoComments", report_in_comments_);
@ -2116,6 +2120,7 @@ void Configuration::impl::accept ()
Q_EMIT self_->decode_highlighting_changed (decode_highlighing_model_);
}
highlight_by_mode_ = ui_->highlight_by_mode_check_box->isChecked ();
include_WAE_entities_ = ui_->include_WAE_check_box->isChecked ();
LotW_days_since_upload_ = ui_->LotW_days_since_upload_spin_box->value ();
lotw_users_.set_age_constraint (LotW_days_since_upload_);

View File

@ -177,6 +177,7 @@ public:
LotWUsers const& lotw_users () const;
DecodeHighlightingModel const& decode_highlighting () const;
bool highlight_by_mode () const;
bool include_WAE_entities () const;
enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, FOX, HOUND};
SpecialOperatingActivity special_op_id () const;

View File

@ -2294,6 +2294,23 @@ Right click for insert and delete options.</string>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout_20">
<item row="0" column="0">
<widget class="QCheckBox" name="include_WAE_check_box"/>
</item>
<item row="0" column="1">
<widget class="QLabel" name="includeExtraWAEEntitiesLabel">
<property name="text">
<string>Include extra WAE entities</string>
</property>
<property name="buddy">
<cstring>include_WAE_check_box</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -2306,35 +2323,6 @@ Right click for insert and delete options.</string>
<string>Logbook of the World User Validation</string>
</property>
<layout class="QFormLayout" name="formLayout_18">
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Age of last upload less than:</string>
</property>
<property name="buddy">
<cstring>LotW_days_since_upload_spin_box</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="LotW_days_since_upload_spin_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="suffix">
<string> days</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>365</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
@ -2369,6 +2357,35 @@ Right click for insert and delete options.</string>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Age of last upload less than:</string>
</property>
<property name="buddy">
<cstring>LotW_days_since_upload_spin_box</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="LotW_days_since_upload_spin_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="suffix">
<string> days</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>365</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -3085,13 +3102,13 @@ Right click for insert and delete options.</string>
</connection>
</connections>
<buttongroups>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
</buttongroups>
</ui>

View File

@ -127,7 +127,7 @@ int DXLabSuiteCommanderTransceiver::do_start ()
throw error {tr ("DX Lab Suite Commander didn't respond correctly reading frequency: ") + reply};
}
poll ();
do_poll ();
return resolution;
}
@ -247,7 +247,7 @@ void DXLabSuiteCommanderTransceiver::do_mode (MODE m)
update_mode (m);
}
void DXLabSuiteCommanderTransceiver::poll ()
void DXLabSuiteCommanderTransceiver::do_poll ()
{
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
bool quiet {false};

View File

@ -39,7 +39,7 @@ protected:
void do_mode (MODE) override;
void do_ptt (bool on) override;
void poll () override;
void do_poll () override;
private:
MODE get_mode (bool no_debug = false);

View File

@ -885,7 +885,7 @@ bool HRDTransceiver::is_button_checked (int button_index, bool no_debug)
return "1" == reply;
}
void HRDTransceiver::poll ()
void HRDTransceiver::do_poll ()
{
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
bool quiet {false};

View File

@ -48,7 +48,7 @@ protected:
void do_ptt (bool on) override;
// Implement the PollingTransceiver interface.
void poll () override;
void do_poll () override;
private:
QString send_command (QString const&, bool no_debug = false, bool prepend_context = true, bool recurse = false);

View File

@ -632,7 +632,7 @@ int HamlibTransceiver::do_start ()
resolution = -1; // best guess
}
poll ();
do_poll ();
TRACE_CAT ("HamlibTransceiver", "exit" << state () << "reversed =" << reversed_ << "resolution = " << resolution);
return resolution;
@ -898,7 +898,7 @@ void HamlibTransceiver::do_mode (MODE mode)
update_mode (mode);
}
void HamlibTransceiver::poll ()
void HamlibTransceiver::do_poll ()
{
#if !WSJT_TRACE_CAT_POLLS
#if defined (NDEBUG)

View File

@ -40,7 +40,7 @@ class HamlibTransceiver final
void do_mode (MODE) override;
void do_ptt (bool) override;
void poll () override;
void do_poll () override;
void error_check (int ret_code, QString const& doing) const;
void set_conf (char const * item, char const * value);

View File

@ -14,17 +14,35 @@
#include "WFPalette.hpp"
#include "models/IARURegions.hpp"
#include "models/DecodeHighlightingModel.hpp"
#include "widgets/FrequencyLineEdit.hpp"
#include "widgets/DateTimeEdit.hpp"
QItemEditorFactory * item_editor_factory ()
namespace
{
static QItemEditorFactory * our_item_editor_factory = new QItemEditorFactory;
return our_item_editor_factory;
class ItemEditorFactory final
: public QItemEditorFactory
{
public:
ItemEditorFactory ()
: default_factory_ {QItemEditorFactory::defaultFactory ()}
{
}
QWidget * createEditor (int user_type, QWidget * parent) const override
{
auto editor = QItemEditorFactory::createEditor (user_type, parent);
return editor ? editor : default_factory_->createEditor (user_type, parent);
}
private:
QItemEditorFactory const * default_factory_;
};
}
void register_types ()
{
auto item_editor_factory = new ItemEditorFactory;
QItemEditorFactory::setDefaultFactory (item_editor_factory);
// types in Radio.hpp are registered in their own translation unit
// as they are needed in the wsjtx_udp shared library too
@ -32,12 +50,7 @@ void register_types ()
// used as signal/slot connection arguments since the new Qt 5.5
// Q_ENUM macro only seems to register the unqualified name
item_editor_factory ()->registerEditor (qMetaTypeId<Radio::Frequency> (), new QStandardItemEditorCreator<FrequencyLineEdit> ());
//auto frequency_delta_type_id = qRegisterMetaType<Radio::FrequencyDelta> ("FrequencyDelta");
item_editor_factory ()->registerEditor (qMetaTypeId<Radio::FrequencyDelta> (), new QStandardItemEditorCreator<FrequencyDeltaLineEdit> ());
auto factory = new QItemEditorFactory;
factory->registerEditor (qMetaTypeId<QDateTime> (), new QStandardItemEditorCreator<DateTimeEdit> ());
QItemEditorFactory::setDefaultFactory (factory);
item_editor_factory->registerEditor (qMetaTypeId<QDateTime> (), new QStandardItemEditorCreator<DateTimeEdit> ());
// Frequency list model
qRegisterMetaTypeStreamOperators<FrequencyList_v2::Item> ("Item_v2");

View File

@ -1,9 +1,6 @@
#ifndef META_DATA_REGISTRY_HPP__
#define META_DATA_REGISTRY_HPP__
class QItemEditorFactory;
QItemEditorFactory * item_editor_factory ();
void register_types ();
#endif

View File

@ -4,6 +4,7 @@
#include <QDebug>
#include <objbase.h>
#include <QThread>
#include <QEventLoop>
#include "qt_helpers.hpP"
@ -109,6 +110,15 @@ OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped
{
}
// returns false on time out
bool OmniRigTransceiver::await_notification_with_timeout (int timeout)
{
QEventLoop el;
connect (this, &OmniRigTransceiver::notified, &el, [&el] () {el.exit (1);});
QTimer::singleShot (timeout, Qt::CoarseTimer, &el, [&el] () {el.exit (0);});
return 1 == el.exec (); // wait for notify or timer
}
int OmniRigTransceiver::do_start ()
{
TRACE_CAT ("OmniRigTransceiver", "starting");
@ -182,101 +192,97 @@ int OmniRigTransceiver::do_start ()
.arg (readable_params_, 8, 16, QChar ('0'))
.arg (writable_params_, 8, 16, QChar ('0'))
.arg (rig_number_).toLocal8Bit ());
offline_timer_.reset (new QTimer);
offline_timer_->setSingleShot (true);
offline_timer_->setInterval (5 * 1000);
connect (&*offline_timer_, &QTimer::timeout, this, &OmniRigTransceiver::timeout_check);
for (unsigned tries {0}; tries < 10; ++tries)
if (OmniRig::ST_ONLINE != rig_->Status ())
{
QThread::msleep (100); // wait until OmniRig polls the rig
auto f = rig_->GetRxFrequency ();
int resolution {0};
if (f)
throw_qstring ("OmniRig: " + rig_->StatusStr ());
}
await_notification_with_timeout (1000);
update_rx_frequency (rig_->GetRxFrequency ());
qDebug () << "Initial state:" << state ();
int resolution {0};
if (OmniRig::PM_UNKNOWN == rig_->Vfo ()
&& (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
== (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
{
// start with VFO A (probably MAIN) on rigs that we
// can't query VFO but can set explicitly
rig_->SetVfo (OmniRig::PM_VFOA);
}
auto f = state ().frequency ();
if (f % 10) return resolution; // 1Hz resolution
auto test_frequency = f - f % 100 + 55;
if (OmniRig::PM_FREQ & writable_params_)
{
rig_->SetFreq (test_frequency);
}
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
{
rig_->SetFreqB (test_frequency);
}
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
{
rig_->SetFreqA (test_frequency);
}
else
{
throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
}
if (!await_notification_with_timeout (1000))
{
TRACE_CAT ("OmniRigTransceiver", "do_start 1: wait timed out");
throw_qstring (tr ("OmniRig: timeout waiting for update from rig"));
}
switch (rig_->GetRxFrequency () - test_frequency)
{
case -5: resolution = -1; break; // 10Hz truncated
case 5: resolution = 1; break; // 10Hz rounded
case -15: resolution = -2; break; // 20Hz truncated
case -55: resolution = -2; break; // 100Hz truncated
case 45: resolution = 2; break; // 100Hz rounded
}
if (1 == resolution) // may be 20Hz rounded
{
test_frequency = f - f % 100 + 51;
if (OmniRig::PM_FREQ & writable_params_)
{
if (OmniRig::PM_UNKNOWN == rig_->Vfo ()
&& (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
== (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
{
// start with VFO A (probably MAIN) on rigs that we
// can't query VFO but can set explicitly
rig_->SetVfo (OmniRig::PM_VFOA);
}
if (f % 10) return resolution; // 1Hz resolution
auto test_frequency = f - f % 100 + 55;
if (OmniRig::PM_FREQ & writable_params_)
{
rig_->SetFreq (test_frequency);
}
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
{
rig_->SetFreqB (test_frequency);
}
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
{
rig_->SetFreqA (test_frequency);
}
else
{
throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
}
switch (rig_->GetRxFrequency () - test_frequency)
{
case -5: resolution = -1; break; // 10Hz truncated
case 5: resolution = 1; break; // 10Hz rounded
case -15: resolution = -2; break; // 20Hz truncated
case -55: resolution = -2; break; // 100Hz truncated
case 45: resolution = 2; break; // 100Hz rounded
}
if (1 == resolution) // may be 20Hz rounded
{
test_frequency = f - f % 100 + 51;
if (OmniRig::PM_FREQ & writable_params_)
{
rig_->SetFreq (test_frequency);
}
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
{
rig_->SetFreqB (test_frequency);
}
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
{
rig_->SetFreqA (test_frequency);
}
if (9 == rig_->GetRxFrequency () - test_frequency)
{
resolution = 2; // 20Hz rounded
}
}
if (OmniRig::PM_FREQ & writable_params_)
{
rig_->SetFreq (f);
}
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
{
rig_->SetFreqB (f);
}
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
{
rig_->SetFreqA (f);
}
update_rx_frequency (f);
return resolution;
rig_->SetFreq (test_frequency);
}
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
{
rig_->SetFreqB (test_frequency);
}
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
{
rig_->SetFreqA (test_frequency);
}
if (!await_notification_with_timeout (2000))
{
TRACE_CAT ("OmniRigTransceiver", "do_start 2: wait timed out");
throw_qstring (tr ("OmniRig: timeout waiting for update from rig"));
}
if (9 == rig_->GetRxFrequency () - test_frequency)
{
resolution = 2; // 20Hz rounded
}
}
throw_qstring (tr ("OmniRig: Initialization timed out"));
return 0; // keep compiler happy
if (OmniRig::PM_FREQ & writable_params_)
{
rig_->SetFreq (f);
}
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
{
rig_->SetFreqB (f);
}
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
{
rig_->SetFreqA (f);
}
update_rx_frequency (f);
return resolution;
}
void OmniRigTransceiver::do_stop ()
{
if (offline_timer_)
{
offline_timer_->stop ();
offline_timer_.reset ();
}
QThread::msleep (200); // leave some time for pending
// commands at the server end
if (port_)
@ -300,17 +306,6 @@ void OmniRigTransceiver::do_stop ()
TRACE_CAT ("OmniRigTransceiver", "stopped");
}
void OmniRigTransceiver::do_sync (bool force_signal, bool /*no_poll*/)
{
// nothing much we can do here, we just have to let OmniRig do its
// stuff and its first poll should send us and update that will
// trigger a update signal from us. Any attempt to query OmniRig
// leads to a whole mess of trouble since its internal state is
// garbage until it has done its first rig poll.
send_update_signal_ = force_signal;
update_complete ();
}
void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help)
{
TRACE_CAT ("OmniRigTransceiver", QString::number (code) + " at " + source + ": " + desc + " (" + help + ')');
@ -319,16 +314,20 @@ void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString
void OmniRigTransceiver::handle_visible_change ()
{
if (!omni_rig_ || omni_rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ());
}
void OmniRigTransceiver::handle_rig_type_change (int rig_number)
{
if (!omni_rig_ || omni_rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", "rig type change: rig =" << rig_number);
if (rig_number_ == rig_number)
{
if (!rig_ || rig_->isNull ()) return;
readable_params_ = rig_->ReadableParams ();
writable_params_ = rig_->WriteableParams ();
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
TRACE_CAT ("OmniRigTransceiver", QString {"rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
.arg (rig_->RigType ())
.arg (readable_params_, 8, 16, QChar ('0'))
.arg (writable_params_, 8, 16, QChar ('0'))
@ -338,48 +337,43 @@ void OmniRigTransceiver::handle_rig_type_change (int rig_number)
void OmniRigTransceiver::handle_status_change (int rig_number)
{
if (!omni_rig_ || omni_rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", QString {"status change for rig %1"}.arg (rig_number).toLocal8Bit ());
if (rig_number_ == rig_number)
{
if (!rig_ || rig_->isNull ()) return;
auto const& status = rig_->StatusStr ().toLocal8Bit ();
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig status change: new status for rig %1 = "}.arg (rig_number).toLocal8Bit () << status);
TRACE_CAT ("OmniRigTransceiver", "OmniRig status change: new status = " << status);
if (OmniRig::ST_ONLINE != rig_->Status ())
{
if (!offline_timer_->isActive ())
{
offline_timer_->start (); // give OmniRig time to recover
}
}
else
{
offline_timer_->stop ();
update_rx_frequency (rig_->GetRxFrequency ());
update_complete ();
TRACE_CAT ("OmniRigTransceiver", "OmniRig frequency:" << state ().frequency ());
offline ("Rig went offline");
}
// else
// {
// update_rx_frequency (rig_->GetRxFrequency ());
// update_complete ();
// TRACE_CAT ("OmniRigTransceiver", "frequency:" << state ().frequency ());
// }
}
}
void OmniRigTransceiver::timeout_check ()
{
offline ("Rig went offline");
}
void OmniRigTransceiver::handle_params_change (int rig_number, int params)
{
if (rig_number_ == rig_number)
{
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig params change: params = 0x%1 for rig %2"}
if (!omni_rig_ || omni_rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", QString {"params change: params = 0x%1 for rig %2"}
.arg (params, 8, 16, QChar ('0'))
.arg (rig_number).toLocal8Bit ()
<< "state before:" << state ());
if (rig_number_ == rig_number)
{
if (!rig_ || rig_->isNull ()) return;
// starting_ = false;
TransceiverState old_state {state ()};
auto need_frequency = false;
// state_.online = true; // sometimes we don't get an initial
// // OmniRig::ST_ONLINE status change
// // event
if (params & OmniRig::PM_VFOAA)
{
TRACE_CAT ("OmniRigTransceiver", "VFOAA");
update_split (false);
reversed_ = false;
update_rx_frequency (rig_->FreqA ());
@ -387,6 +381,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
}
if (params & OmniRig::PM_VFOAB)
{
TRACE_CAT ("OmniRigTransceiver", "VFOAB");
update_split (true);
reversed_ = false;
update_rx_frequency (rig_->FreqA ());
@ -394,6 +389,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
}
if (params & OmniRig::PM_VFOBA)
{
TRACE_CAT ("OmniRigTransceiver", "VFOBA");
update_split (true);
reversed_ = true;
update_other_frequency (rig_->FreqA ());
@ -401,6 +397,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
}
if (params & OmniRig::PM_VFOBB)
{
TRACE_CAT ("OmniRigTransceiver", "VFOBB");
update_split (false);
reversed_ = true;
update_other_frequency (rig_->FreqA ());
@ -408,64 +405,75 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
}
if (params & OmniRig::PM_VFOA)
{
TRACE_CAT ("OmniRigTransceiver", "VFOA");
reversed_ = false;
need_frequency = true;
}
if (params & OmniRig::PM_VFOB)
{
TRACE_CAT ("OmniRigTransceiver", "VFOB");
reversed_ = true;
need_frequency = true;
}
if (params & OmniRig::PM_FREQ)
{
TRACE_CAT ("OmniRigTransceiver", "FREQ");
need_frequency = true;
}
if (params & OmniRig::PM_FREQA)
{
auto f = rig_->FreqA ();
TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f);
if (reversed_)
{
update_other_frequency (rig_->FreqA ());
update_other_frequency (f);
}
else
{
update_rx_frequency (rig_->FreqA ());
update_rx_frequency (f);
}
}
if (params & OmniRig::PM_FREQB)
{
auto f = rig_->FreqB ();
TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f);
if (reversed_)
{
update_rx_frequency (rig_->FreqB ());
update_rx_frequency (f);
}
else
{
update_other_frequency (rig_->FreqB ());
update_other_frequency (f);
}
}
if (need_frequency)
{
if (readable_params_ & OmniRig::PM_FREQA)
{
auto f = rig_->FreqA ();
TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f);
if (reversed_)
{
update_other_frequency (rig_->FreqA ());
update_other_frequency (f);
}
else
{
update_rx_frequency (rig_->FreqA ());
update_rx_frequency (f);
}
need_frequency = false;
}
if (readable_params_ & OmniRig::PM_FREQB)
{
auto f = rig_->FreqB ();
TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f);
if (reversed_)
{
update_rx_frequency (rig_->FreqB ());
update_rx_frequency (f);
}
else
{
update_other_frequency (rig_->FreqB ());
update_other_frequency (f);
}
need_frequency = false;
}
@ -473,89 +481,113 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
if (need_frequency && (readable_params_ & OmniRig::PM_FREQ)
&& !state ().ptt ())
{
update_rx_frequency (rig_->Freq ());
auto f = rig_->Freq ();
TRACE_CAT ("OmniRigTransceiver", "FREQ = " << f);
update_rx_frequency (f);
}
if (params & OmniRig::PM_PITCH)
{
TRACE_CAT ("OmniRigTransceiver", "PITCH");
}
if (params & OmniRig::PM_RITOFFSET)
{
TRACE_CAT ("OmniRigTransceiver", "RITOFFSET");
}
if (params & OmniRig::PM_RIT0)
{
TRACE_CAT ("OmniRigTransceiver", "RIT0");
}
if (params & OmniRig::PM_VFOEQUAL)
{
auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq ();
auto m = map_mode (rig_->Mode ());
TRACE_CAT ("OmniRigTransceiver", QString {"VFOEQUAL f=%1 m=%2"}.arg (f).arg (m));
update_rx_frequency (f);
update_other_frequency (f);
update_mode (map_mode (rig_->Mode ()));
update_mode (m);
}
if (params & OmniRig::PM_VFOSWAP)
{
auto temp = state ().tx_frequency ();
TRACE_CAT ("OmniRigTransceiver", "VFOSWAP");
auto f = state ().tx_frequency ();
update_other_frequency (state ().frequency ());
update_rx_frequency (temp);
update_rx_frequency (f);
update_mode (map_mode (rig_->Mode ()));
}
if (params & OmniRig::PM_SPLITON)
{
TRACE_CAT ("OmniRigTransceiver", "SPLITON");
update_split (true);
}
if (params & OmniRig::PM_SPLITOFF)
{
TRACE_CAT ("OmniRigTransceiver", "SPLITOFF");
update_split (false);
}
if (params & OmniRig::PM_RITON)
{
TRACE_CAT ("OmniRigTransceiver", "RITON");
}
if (params & OmniRig::PM_RITOFF)
{
TRACE_CAT ("OmniRigTransceiver", "RITOFF");
}
if (params & OmniRig::PM_XITON)
{
TRACE_CAT ("OmniRigTransceiver", "XITON");
}
if (params & OmniRig::PM_XITOFF)
{
TRACE_CAT ("OmniRigTransceiver", "XITOFF");
}
if (params & OmniRig::PM_RX)
{
TRACE_CAT ("OmniRigTransceiver", "RX");
update_PTT (false);
}
if (params & OmniRig::PM_TX)
{
TRACE_CAT ("OmniRigTransceiver", "TX");
update_PTT ();
}
if (params & OmniRig::PM_CW_U)
{
TRACE_CAT ("OmniRigTransceiver", "CW-R");
update_mode (CW_R);
}
if (params & OmniRig::PM_CW_L)
{
TRACE_CAT ("OmniRigTransceiver", "CW");
update_mode (CW);
}
if (params & OmniRig::PM_SSB_U)
{
TRACE_CAT ("OmniRigTransceiver", "USB");
update_mode (USB);
}
if (params & OmniRig::PM_SSB_L)
{
TRACE_CAT ("OmniRigTransceiver", "LSB");
update_mode (LSB);
}
if (params & OmniRig::PM_DIG_U)
{
TRACE_CAT ("OmniRigTransceiver", "DATA-U");
update_mode (DIG_U);
}
if (params & OmniRig::PM_DIG_L)
{
TRACE_CAT ("OmniRigTransceiver", "DATA-L");
update_mode (DIG_L);
}
if (params & OmniRig::PM_AM)
{
TRACE_CAT ("OmniRigTransceiver", "AM");
update_mode (AM);
}
if (params & OmniRig::PM_FM)
{
TRACE_CAT ("OmniRigTransceiver", "FM");
update_mode (FM);
}
@ -566,6 +598,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
}
TRACE_CAT ("OmniRigTransceiver", "OmniRig params change: state after:" << state ());
}
Q_EMIT notified ();
}
void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& command, QVariant const& reply)
@ -573,8 +606,10 @@ void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& co
(void)command;
(void)reply;
if (!omni_rig_ || omni_rig_->isNull ()) return;
if (rig_number_ == rig_number)
{
if (!rig_ || rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit ()
<< "with reply" << reply.toString ().toLocal8Bit ()
<< QString ("for rig %1").arg (rig_number).toLocal8Bit ());

View File

@ -38,10 +38,11 @@ public:
void do_tx_frequency (Frequency, MODE, bool no_ignore) override;
void do_mode (MODE) override;
void do_ptt (bool on) override;
void do_sync (bool force_signal, bool no_poll) override;
private:
Q_SLOT void timeout_check ();
bool await_notification_with_timeout (int timeout);
Q_SIGNAL void notified () const;
// Q_SLOT void timeout_check ();
Q_SLOT void handle_COM_exception (int, QString, QString, QString);
Q_SLOT void handle_visible_change ();
Q_SLOT void handle_rig_type_change (int rig_number);
@ -62,7 +63,7 @@ private:
QString rig_type_;
int readable_params_;
int writable_params_;
QScopedPointer<QTimer> offline_timer_;
// QScopedPointer<QTimer> offline_timer_;
bool send_update_signal_;
bool reversed_; // some rigs can reverse VFOs
};

View File

@ -129,52 +129,46 @@ bool PollingTransceiver::do_pre_update ()
return true;
}
void PollingTransceiver::do_sync (bool force_signal, bool no_poll)
{
if (!no_poll) poll (); // tell sub-classes to update our state
// Signal new state if it is directly requested or, what we expected
// or, hasn't become what we expected after polls_to_stabilize
// polls. Unsolicited changes will be signalled immediately unless
// they intervene in a expected sequence where they will be delayed.
if (retries_)
{
--retries_;
if (force_signal || state () == next_state_ || !retries_)
{
// our client wants a signal regardless
// or the expected state has arrived
// or there are no more retries
force_signal = true;
}
}
else if (force_signal || state () != last_signalled_state_)
{
// here is the normal passive polling path either our client has
// requested a state update regardless of change or state has
// changed asynchronously
force_signal = true;
}
if (force_signal)
{
// reset everything, record and signal the current state
retries_ = 0;
next_state_ = state ();
last_signalled_state_ = state ();
update_complete (true);
}
}
void PollingTransceiver::handle_timeout ()
{
QString message;
bool force_signal {false};
// we must catch all exceptions here since we are called by Qt and
// inform our parent of the failure via the offline() message
try
{
do_sync ();
do_poll (); // tell sub-classes to update our state
// Signal new state if it what we expected or, hasn't become
// what we expected after polls_to_stabilize polls. Unsolicited
// changes will be signalled immediately unless they intervene
// in a expected sequence where they will be delayed.
if (retries_)
{
--retries_;
if (state () == next_state_ || !retries_)
{
// the expected state has arrived or there are no more
// retries
force_signal = true;
}
}
else if (state () != last_signalled_state_)
{
// here is the normal passive polling path where state has
// changed asynchronously
force_signal = true;
}
if (force_signal)
{
// reset everything, record and signal the current state
retries_ = 0;
next_state_ = state ();
last_signalled_state_ = state ();
update_complete (true);
}
}
catch (std::exception const& e)
{

View File

@ -39,11 +39,9 @@ protected:
QObject * parent);
protected:
void do_sync (bool force_signal = false, bool no_poll = false) override final;
// Sub-classes implement this and fetch what they can from the rig
// in a non-intrusive manner.
virtual void poll () = 0;
virtual void do_poll () = 0;
void do_post_start () override final;
void do_post_stop () override final;

View File

@ -74,14 +74,14 @@ namespace Radio
}
QString frequency_MHz_string (Frequency f, QLocale const& locale)
QString frequency_MHz_string (Frequency f, int precision, QLocale const& locale)
{
return locale.toString (f / MHz_factor, 'f', frequency_precsion);
return locale.toString (f / MHz_factor, 'f', precision);
}
QString frequency_MHz_string (FrequencyDelta d, QLocale const& locale)
QString frequency_MHz_string (FrequencyDelta d, int precision, QLocale const& locale)
{
return locale.toString (d / MHz_factor, 'f', frequency_precsion);
return locale.toString (d / MHz_factor, 'f', precision);
}
QString pretty_frequency_MHz_string (Frequency f, QLocale const& locale)

View File

@ -42,8 +42,8 @@ namespace Radio
//
// Frequency type formatting
//
QString UDP_EXPORT frequency_MHz_string (Frequency, QLocale const& = QLocale ());
QString UDP_EXPORT frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ());
QString UDP_EXPORT frequency_MHz_string (Frequency, int precision = 6, QLocale const& = QLocale ());
QString UDP_EXPORT frequency_MHz_string (FrequencyDelta, int precision = 6, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (Frequency, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (double, int scale, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ());

View File

@ -40,6 +40,8 @@ OTHER IMPROVEMENTS
- N1MM Logger+ now uses the standard WSJT-X UDP messages
- OK/Cancel buttons on Log QSO window maintain fixed positions
- Put EU VHF contest serial numbers into the ADIF SRX and STX fields
- Enhancements to the Omni-Rig CAT interface
- New setting option to include or exclude WAE entities
BUG FIXES
- Fix generation of Tx5 message when one callsign is nonstandard
@ -47,6 +49,7 @@ BUG FIXES
- Fix a bug that caused mode switch from FT4 to FT8
- Fix a bug that caused FT4 to do WSPR-style band hopping
- Fix a bug that caused a Fortran bounds error
- Repaired field editing in the Contest Log window
Release candidate WSJT-X 2.1.0-rc6 will be available for beta-testing
through July 21, 2019. It will be inoperable during the ARRL June VHF

View File

@ -19,10 +19,10 @@ void TransceiverBase::start (unsigned sequence_number) noexcept
QString message;
try
{
last_sequence_number_ = sequence_number;
may_update u {this, true};
shutdown ();
startup ();
last_sequence_number_ = sequence_number;
}
catch (std::exception const& e)
{
@ -46,6 +46,7 @@ void TransceiverBase::set (TransceiverState const& s,
QString message;
try
{
last_sequence_number_ = sequence_number;
may_update u {this, true};
bool was_online {requested_.online ()};
if (!s.online () && was_online)
@ -115,7 +116,6 @@ void TransceiverBase::set (TransceiverState const& s,
// record what actually changed
requested_.ptt (actual_.ptt ());
}
last_sequence_number_ = sequence_number;
}
catch (std::exception const& e)
{
@ -133,10 +133,27 @@ void TransceiverBase::set (TransceiverState const& s,
void TransceiverBase::startup ()
{
Q_EMIT resolution (do_start ());
do_post_start ();
actual_.online (true);
requested_.online (true);
QString message;
try
{
actual_.online (true);
requested_.online (true);
auto res = do_start ();
do_post_start ();
Q_EMIT resolution (res);
}
catch (std::exception const& e)
{
message = e.what ();
}
catch (...)
{
message = unexpected;
}
if (!message.isEmpty ())
{
offline (message);
}
}
void TransceiverBase::shutdown ()
@ -163,8 +180,8 @@ void TransceiverBase::shutdown ()
}
do_stop ();
do_post_stop ();
actual_.online (false);
requested_.online (false);
actual_ = TransceiverState {};
requested_ = TransceiverState {};
}
void TransceiverBase::stop () noexcept

View File

@ -112,8 +112,6 @@ protected:
virtual void do_ptt (bool = true) = 0;
virtual void do_post_ptt (bool = true) {}
virtual void do_sync (bool force_signal = false, bool no_poll = false) = 0;
virtual bool do_pre_update () {return true;}
// sub classes report rig state changes with these methods

View File

@ -2,5 +2,5 @@
set (WSJTX_VERSION_MAJOR 2)
set (WSJTX_VERSION_MINOR 1)
set (WSJTX_VERSION_PATCH 0)
set (WSJTX_RC 6) # release candidate number, comment out or zero for development versions
set (WSJTX_RC 7) # release candidate number, comment out or zero for development versions
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build

View File

@ -0,0 +1,27 @@
#include "FrequencyDelegate.hpp"
#include "widgets/FrequencyLineEdit.hpp"
FrequencyDelegate::FrequencyDelegate (QObject * parent)
: QStyledItemDelegate {parent}
{
}
QWidget * FrequencyDelegate::createEditor (QWidget * parent, QStyleOptionViewItem const&
, QModelIndex const&) const
{
auto * editor = new FrequencyLineEdit {parent};
editor->setFrame (false);
return editor;
}
void FrequencyDelegate::setEditorData (QWidget * editor, QModelIndex const& index) const
{
static_cast<FrequencyLineEdit *> (editor)->frequency (index.model ()->data (index, Qt::EditRole).value<Radio::Frequency> ());
}
void FrequencyDelegate::setModelData (QWidget * editor, QAbstractItemModel * model, QModelIndex const& index) const
{
model->setData (index, static_cast<FrequencyLineEdit *> (editor)->frequency (), Qt::EditRole);
}

View File

@ -0,0 +1,21 @@
#ifndef FREQUENCY_DELEGATE_HPP_
#define FREQUENCY_DELEGATE_HPP_
#include <QStyledItemDelegate>
//
// Class FrequencyDelegate
//
// Item delegate for editing a frequency in Hertz but displayed in MHz
//
class FrequencyDelegate final
: public QStyledItemDelegate
{
public:
explicit FrequencyDelegate (QObject * parent = nullptr);
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
void setEditorData (QWidget * editor, QModelIndex const&) const override;
void setModelData (QWidget * editor, QAbstractItemModel *, QModelIndex const&) const override;
};
#endif

View File

@ -0,0 +1,26 @@
#include "FrequencyDeltaDelegate.hpp"
#include "widgets/FrequencyDeltaLineEdit.hpp"
FrequencyDeltaDelegate::FrequencyDeltaDelegate (QObject * parent)
: QStyledItemDelegate {parent}
{
}
QWidget * FrequencyDeltaDelegate::createEditor (QWidget * parent, QStyleOptionViewItem const&
, QModelIndex const&) const
{
auto * editor = new FrequencyDeltaLineEdit {parent};
editor->setFrame (false);
return editor;
}
void FrequencyDeltaDelegate::setEditorData (QWidget * editor, QModelIndex const& index) const
{
static_cast<FrequencyDeltaLineEdit *> (editor)->frequency_delta (index.model ()->data (index, Qt::EditRole).value<Radio::FrequencyDelta> ());
}
void FrequencyDeltaDelegate::setModelData (QWidget * editor, QAbstractItemModel * model, QModelIndex const& index) const
{
model->setData (index, static_cast<FrequencyDeltaLineEdit *> (editor)->frequency_delta (), Qt::EditRole);
}

View File

@ -0,0 +1,21 @@
#ifndef FREQUENCY_DELTA_DELEGATE_HPP_
#define FREQUENCY_DELTA_DELEGATE_HPP_
#include <QStyledItemDelegate>
//
// Class FrequencyDeltaDelegate
//
// Item delegate for editing a frequency delta in Hertz but displayed in MHz
//
class FrequencyDeltaDelegate final
: public QStyledItemDelegate
{
public:
explicit FrequencyDeltaDelegate (QObject * parent = nullptr);
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
void setEditorData (QWidget * editor, QModelIndex const&) const override;
void setModelData (QWidget * editor, QAbstractItemModel *, QModelIndex const&) const override;
};
#endif

View File

@ -1,11 +1,13 @@
SOURCES += \
item_delegates/ForeignKeyDelegate.cpp \
item_delegates/FrequencyItemDelegate.cpp \
item_delegates/FrequencyDelegate.cpp \
item_delegates/FrequencyDeltaDelegate.cpp \
item_delegates/CallsignDelegate.cpp \
item_delegates/MaidenheadLocatorItemDelegate.cpp
HEADERS += \
item_delegates/ForeignKeyDelegate.hpp \
item_delegates/FrequencyItemDelegate.hpp \
item_delegates/FrequencyDelegate.hpp \
item_delegates/FrequencyDeltaDelegate.hpp \
item_delegates/CallsignDelegate.hpp \
item_delegates/MaidenheadLocatorDelegate.hpp

View File

@ -16,6 +16,7 @@
#include <QTextStream>
#include <QDebug>
#include <QDebugStateSaver>
#include "Configuration.hpp"
#include "Radio.hpp"
#include "pimpl_impl.hpp"
@ -155,14 +156,16 @@ typedef multi_index_container<
class AD1CCty::impl final
{
public:
explicit impl ()
using entity_by_id = entities_type::index<id>::type;
explicit impl (Configuration const * configuration)
: configuration_ {configuration}
{
}
Record fixup (QString call, prefix const& p) const
entity_by_id::iterator lookup_entity (QString call, prefix const& p) const
{
call = call.toUpper ();
using entity_by_id = entities_type::index<id>::type;
entity_by_id::iterator e; // iterator into entity set
//
@ -171,23 +174,26 @@ public:
if (call.startsWith ("KG4") && call.size () != 5 && call.size () != 3)
{
// KG4 2x1 and 2x3 calls that map to Gitmo are mainland US not Gitmo
e = entities_.project<id> (entities_.get<primary_prefix> ().find ("K"));
return entities_.project<id> (entities_.get<primary_prefix> ().find ("K"));
}
else
{
e = entities_.get<id> ().find (p.entity_id_);
return entities_.get<id> ().find (p.entity_id_);
}
}
Record fixup (prefix const& p, entity const& e) const
{
Record result;
result.continent = e->continent_;
result.CQ_zone = e->CQ_zone_;
result.ITU_zone = e->ITU_zone_;
result.entity_name = e->name_;
result.WAE_only = e->WAE_only_;
result.latitude = e->lat_;
result.longtitude = e->long_;
result.UTC_offset = e->UTC_offset_;
result.primary_prefix = e->primary_prefix_;
result.continent = e.continent_;
result.CQ_zone = e.CQ_zone_;
result.ITU_zone = e.ITU_zone_;
result.entity_name = e.name_;
result.WAE_only = e.WAE_only_;
result.latitude = e.lat_;
result.longtitude = e.long_;
result.UTC_offset = e.UTC_offset_;
result.primary_prefix = e.primary_prefix_;
// check for overrides
bool ok1 {true}, ok2 {true}, ok3 {true}, ok4 {true}, ok5 {true};
@ -220,6 +226,7 @@ public:
return false;
}
Configuration const * configuration_;
QString path_;
entities_type entities_;
prefixes_type prefixes_;
@ -307,8 +314,13 @@ char const * AD1CCty::continent (Continent c)
}
}
AD1CCty::AD1CCty ()
AD1CCty::AD1CCty (Configuration const * configuration)
: m_ {configuration}
{
Q_ASSERT (configuration);
// TODO: G4WJS - consider doing the following asynchronously to
// speed up startup. Not urgent as it takes less than 1s on a Core
// i7 reading BIG CTY.DAT.
QDir dataPath {QStandardPaths::writableLocation (QStandardPaths::DataLocation)};
m_->path_ = dataPath.exists (file_name)
? dataPath.absoluteFilePath (file_name) // user override
@ -389,7 +401,7 @@ auto AD1CCty::lookup (QString const& call) const -> Record
auto p = m_->prefixes_.find (exact_search);
if (p != m_->prefixes_.end () && p->exact_)
{
return m_->fixup (call, *p);
return m_->fixup (*p, *m_->lookup_entity (call, *p));
}
}
while (search_prefix.size ())
@ -397,9 +409,11 @@ auto AD1CCty::lookup (QString const& call) const -> Record
auto p = m_->prefixes_.find (search_prefix);
if (p != m_->prefixes_.end ())
{
if (!p->exact_ || call.size () == search_prefix.size ())
impl::entity_by_id::iterator e = m_->lookup_entity (call, *p);
if ((m_->configuration_->include_WAE_entities () || !e->WAE_only_)
&& (!p->exact_ || call.size () == search_prefix.size ()))
{
return m_->fixup (call, *p);
return m_->fixup (*p, *e);
}
}
search_prefix = search_prefix.left (search_prefix.size () - 1);

View File

@ -1,17 +1,19 @@
#ifndef AD1C_CTY_HPP_
#define AD1C_CTY_HPP_
#include <boost/core/noncopyable.hpp>
#include <QObject>
#include <QDebug>
#include "pimpl_h.hpp"
class QString;
class Configuration;
//
// AD1CCty - Fast access database of Jim Reisert, AD1C's, cty.dat
// entity and entity override information file.
//
class AD1CCty final
: public QObject
, private boost::noncopyable
{
Q_OBJECT
@ -39,7 +41,7 @@ public:
QString primary_prefix;
};
explicit AD1CCty ();
explicit AD1CCty (Configuration const *);
~AD1CCty ();
Record lookup (QString const& call) const;

44
logbook/Multiplier.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "Multiplier.hpp"
#include <QSet>
#include <QString>
#include <QDebug>
#include "models/CabrilloLog.hpp"
#include "pimpl_impl.hpp"
class Multiplier::impl
{
public:
impl (AD1CCty const * countries)
: countries_ {countries}
{
}
AD1CCty const * countries_;
worked_set entities_worked_;
worked_set grids_worked_;
};
Multiplier::Multiplier (AD1CCty const * countries)
: m_ {countries}
{
}
Multiplier::~Multiplier ()
{
}
void Multiplier::reload (CabrilloLog const * log)
{
m_->entities_worked_ = log->unique_DXCC_entities (m_->countries_);
}
auto Multiplier::entities_worked () const -> worked_set const&
{
return m_->entities_worked_;
}
auto Multiplier::grids_worked () const -> worked_set const&
{
return m_->grids_worked_;
}

30
logbook/Multiplier.hpp Normal file
View File

@ -0,0 +1,30 @@
#ifndef MULTIPLIER_HPP_
#define MULTIPLIER_HPP_
#include <boost/core/noncopyable.hpp>
#include <QSet>
#include "pimpl_h.hpp"
class QString;
class AD1CCty;
class CabrilloLog;
class Multiplier final
: private boost::noncopyable
{
public:
using worked_item = QPair<QString, QString>;
using worked_set = QSet<worked_item>;
explicit Multiplier (AD1CCty const *);
~Multiplier ();
void reload (CabrilloLog const *);
worked_set const& entities_worked () const;
worked_set const& grids_worked () const;
private:
class impl;
pimpl<impl> m_;
};
#endif

View File

@ -18,7 +18,7 @@
#include <QFileInfo>
#include <QFile>
#include <QTextStream>
#include "Configuration.hpp"
#include "qt_helpers.hpp"
#include "pimpl_impl.hpp"
@ -361,8 +361,9 @@ namespace
class WorkedBefore::impl final
{
public:
impl ()
impl (Configuration const * configuration)
: path_ {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (logFileName)}
, prefixes_ {configuration}
{
}
@ -379,8 +380,10 @@ public:
worked_before_database_type worked_;
};
WorkedBefore::WorkedBefore ()
WorkedBefore::WorkedBefore (Configuration const * configuration)
: m_ {configuration}
{
Q_ASSERT (configuration);
connect (&m_->loader_watcher_, &QFutureWatcher<worked_before_database_type>::finished, [this] () {
QString error;
size_t n {0};
@ -412,9 +415,9 @@ QString const& WorkedBefore::path () const
return m_->path_;
}
AD1CCty const& WorkedBefore::countries () const
AD1CCty const * WorkedBefore::countries () const
{
return m_->prefixes_;
return &m_->prefixes_;
}
bool WorkedBefore::add (QString const& call

View File

@ -5,6 +5,7 @@
#include "AD1CCty.hpp"
#include "pimpl_h.hpp"
class Configuration;
class CountryDat;
class QString;
class QByteArray;
@ -17,7 +18,7 @@ class WorkedBefore final
public:
using Continent = AD1CCty::Continent;
explicit WorkedBefore ();
explicit WorkedBefore (Configuration const *);
~WorkedBefore ();
Q_SLOT void reload ();
@ -28,7 +29,7 @@ public:
, QByteArray const& ADIF_record);
QString const& path () const;
AD1CCty const& countries () const;
AD1CCty const * countries () const;
bool country_worked (QString const& call, QString const& mode, QString const& band) const;
bool grid_worked (QString const& grid, QString const& mode, QString const& band) const;
bool call_worked (QString const& call, QString const& mode, QString const& band) const;

View File

@ -3,15 +3,25 @@
#include <QDateTime>
#include "Configuration.hpp"
#include "AD1CCty.hpp"
#include "Multiplier.hpp"
#include "logbook/AD1CCty.hpp"
#include "models/CabrilloLog.hpp"
#include "models/FoxLog.hpp"
#include "moc_logbook.cpp"
LogBook::LogBook (Configuration const * configuration)
: config_ {configuration}
, worked_before_ {configuration}
{
Q_ASSERT (configuration);
connect (&worked_before_, &WorkedBefore::finished_loading, this, &LogBook::finished_loading);
}
LogBook::~LogBook ()
{
}
void LogBook::match (QString const& call, QString const& mode, QString const& grid,
AD1CCty::Record const& looked_up,
bool& callB4,
@ -136,3 +146,40 @@ QByteArray LogBook::QSOToADIF (QString const& hisCall, QString const& hisGrid, Q
}
return t.toLatin1();
}
CabrilloLog * LogBook::contest_log ()
{
// lazy create of Cabrillo log object instance
if (!contest_log_)
{
contest_log_.reset (new CabrilloLog {config_});
if (!multiplier_)
{
multiplier_.reset (new Multiplier {countries ()});
}
connect (contest_log_.data (), &CabrilloLog::data_changed, [this] () {
multiplier_->reload (contest_log_.data ());
});
}
return contest_log_.data ();
}
Multiplier const * LogBook::multiplier () const
{
// lazy create of Multiplier object instance
if (!multiplier_)
{
multiplier_.reset (new Multiplier {countries ()});
}
return multiplier_.data ();
}
FoxLog * LogBook::fox_log ()
{
// lazy create of Fox log object instance
if (!fox_log_)
{
fox_log_.reset (new FoxLog {config_});
}
return fox_log_.data ();
}

View File

@ -8,12 +8,16 @@
#include <QObject>
#include <QString>
#include <QScopedPointer>
#include "WorkedBefore.hpp"
class Configuration;
class QByteArray;
class QDateTime;
class CabrilloLog;
class Multiplier;
class FoxLog;
class LogBook final
: public QObject
@ -22,13 +26,14 @@ class LogBook final
public:
LogBook (Configuration const *);
~LogBook ();
QString const& path () const {return worked_before_.path ();}
bool add (QString const& call
, QString const& grid
, QString const& band
, QString const& mode
, QByteArray const& ADIF_record);
AD1CCty const& countries () const {return worked_before_.countries ();}
AD1CCty const * countries () const {return worked_before_.countries ();}
void rescan ();
void match (QString const& call, QString const& mode, QString const& grid,
AD1CCty::Record const&, bool& callB4, bool& countryB4,
@ -43,9 +48,16 @@ public:
Q_SIGNAL void finished_loading (int worked_before_record_count, QString const& error) const;
CabrilloLog * contest_log ();
Multiplier const * multiplier () const;
FoxLog * fox_log ();
private:
Configuration const * config_;
WorkedBefore worked_before_;
QScopedPointer<CabrilloLog> contest_log_;
QScopedPointer<Multiplier> mutable multiplier_;
QScopedPointer<FoxLog> fox_log_;
};
#endif

View File

@ -2,10 +2,12 @@ SOURCES += \
logbook/countriesworked.cpp \
logbook/logbook.cpp \
logbook/AD1CCty.cpp \
logbook/WorkedBefore.cpp
logbook/WorkedBefore.cpp \
logbook/Multiplier.cpp
HEADERS += \
logbook/WorkedBefore.hpp \
logbook/logbook.h \
logbook/countriesworked.h \
logbook/AD1CCty.hpp
logbook/AD1CCty.hpp \
logbook/Multiplier.hpp

View File

@ -380,10 +380,12 @@ int main(int argc, char *argv[])
}
catch (std::exception const& e)
{
MessageBox::critical_message (nullptr, QApplication::translate ("main", "Fatal error"), e.what ());
std::cerr << "Error: " << e.what () << '\n';
}
catch (...)
{
MessageBox::critical_message (nullptr, QApplication::translate ("main", "Unexpected fatal error"));
std::cerr << "Unexpected fatal error\n";
throw; // hoping the runtime might tell us more about the exception
}

View File

@ -12,6 +12,7 @@
#include <QDataStream>
#include "Configuration.hpp"
#include "Bands.hpp"
#include "logbook/AD1CCty.hpp"
#include "qt_db_helpers.hpp"
#include "pimpl_impl.hpp"
@ -19,59 +20,109 @@ class CabrilloLog::impl final
: public QSqlTableModel
{
public:
impl (Configuration const *);
impl (CabrilloLog *, Configuration const *);
QVariant data (QModelIndex const& index, int role) const
int columnCount (QModelIndex const& /*index */) const override
{
auto value = QSqlTableModel::data (index, role);
if (index.column () == fieldIndex ("when")
&& (Qt::DisplayRole == role || Qt::EditRole == role))
return QSqlTableModel::columnCount () + 1;
}
Qt::ItemFlags flags (QModelIndex const& index) const override
{
auto flags = QSqlTableModel::flags (index);
if (index.isValid () && index.column () == columnCount (index) - 1)
{
auto t = QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC);
flags = Qt::ItemIsEnabled;
}
return flags;
}
QVariant data (QModelIndex const& model_index, int role) const override
{
QVariant value;
if (model_index.isValid () && model_index.column () == columnCount (model_index) - 1)
{ // derive band column
if (Qt::DisplayRole == role)
{
QLocale locale;
return locale.toString (t, locale.dateFormat (QLocale::ShortFormat) + " hh:mm:ss");
value = configuration_->bands ()->find (QSqlTableModel::data (index (model_index.row (), fieldIndex ("frequency"))).toULongLong ());
}
}
else
{
value = QSqlTableModel::data (model_index, role);
if (model_index.column () == fieldIndex ("frequency") && Qt::DisplayRole == role)
{
value = Radio::frequency_MHz_string (value.value<Radio::Frequency> (), 3); // kHz precision
}
else if (model_index.column () == fieldIndex ("when")
&& (Qt::DisplayRole == role || Qt::EditRole == role))
{ // adjust date/time to Qt format
auto t = QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC);
if (Qt::DisplayRole == role)
{
QLocale locale;
return locale.toString (t, locale.dateFormat (QLocale::ShortFormat) + " hh:mm:ss");
}
value = t;
}
value = t;
}
return value;
}
QString cabrillo_frequency_string (Radio::Frequency frequency) const;
void create_table ();
CabrilloLog * self_;
Configuration const * configuration_;
QSqlQuery mutable dupe_query_;
QSqlQuery mutable export_query_;
bool adding_row_;
};
CabrilloLog::impl::impl (Configuration const * configuration)
: QSqlTableModel {}
CabrilloLog::impl::impl (CabrilloLog * self, Configuration const * configuration)
: self_ {self}
, configuration_ {configuration}
, adding_row_ {false}
{
if (!database ().tables ().contains ("cabrillo_log"))
if (!database ().tables ().contains ("cabrillo_log_v2"))
{
QSqlQuery query;
SQL_error_check (query, static_cast<bool (QSqlQuery::*) (QString const&)> (&QSqlQuery::exec),
"CREATE TABLE cabrillo_log ("
" id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
" frequency INTEGER NOT NULL,"
" \"when\" DATETIME NOT NULL,"
" call VARCHAR(20) NOT NULL,"
" exchange_sent VARCHAR(32) NOT NULL,"
" exchange_rcvd VARCHAR(32) NOT NULL,"
" band VARCHAR(6) NOT NULL"
")");
create_table ();
}
setEditStrategy (QSqlTableModel::OnFieldChange);
setTable ("cabrillo_log_v2");
setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(MHz)"));
setHeaderData (fieldIndex ("mode"), Qt::Horizontal, tr ("Mode"));
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)"));
setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call"));
setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent"));
setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd"));
setHeaderData (columnCount (QModelIndex {}) - 1, Qt::Horizontal, tr ("Band"));
// This descending order by time is important, it makes the view
// place the latest row at the top, without this the model/view
// interactions are both sluggish and unhelpful.
setSort (fieldIndex ("when"), Qt::DescendingOrder);
connect (this, &CabrilloLog::impl::modelReset, self_, &CabrilloLog::data_changed);
connect (this, &CabrilloLog::impl::dataChanged, [this] (QModelIndex const& tl, QModelIndex const& br) {
if (!adding_row_ && !(tl == br)) // ignore single cell changes
// as a another change for the
// whole row will follow
{
Q_EMIT self_->data_changed ();
}
});
SQL_error_check (*this, &QSqlTableModel::select);
SQL_error_check (dupe_query_, &QSqlQuery::prepare,
"SELECT "
" COUNT(*) "
" frequency "
" FROM "
" cabrillo_log "
" cabrillo_log_v2 "
" WHERE "
" call = :call "
" AND band = :band");
" call = :call ");
SQL_error_check (export_query_, &QSqlQuery::prepare,
"SELECT "
@ -81,32 +132,31 @@ CabrilloLog::impl::impl (Configuration const * configuration)
" , call"
" , exchange_rcvd"
" FROM "
" cabrillo_log "
" cabrillo_log_v2 "
" ORDER BY "
" \"when\"");
setEditStrategy (QSqlTableModel::OnFieldChange);
setTable ("cabrillo_log");
setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(kHz)"));
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)"));
setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call"));
setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent"));
setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd"));
setHeaderData (fieldIndex ("band"), Qt::Horizontal, tr ("Band"));
}
// This descending order by time is important, it makes the view
// place the latest row at the top, without this the model/view
// interactions are both sluggish and unhelpful.
setSort (fieldIndex ("when"), Qt::DescendingOrder);
SQL_error_check (*this, &QSqlTableModel::select);
void CabrilloLog::impl::create_table ()
{
QSqlQuery query;
SQL_error_check (query, static_cast<bool (QSqlQuery::*) (QString const&)> (&QSqlQuery::exec),
"CREATE TABLE cabrillo_log_v2 ("
" id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
" frequency INTEGER NOT NULL,"
" mode VARCHAR(6) NOT NULL,"
" \"when\" DATETIME NOT NULL,"
" call VARCHAR(20) NOT NULL,"
" exchange_sent VARCHAR(32) NOT NULL,"
" exchange_rcvd VARCHAR(32) NOT NULL"
")");
}
// frequency here is in kHz
QString CabrilloLog::impl::cabrillo_frequency_string (Radio::Frequency frequency) const
{
QString result;
auto band = configuration_->bands ()->find (frequency * 1000ull);
auto band = configuration_->bands ()->find (frequency);
if ("1mm" == band) result = "LIGHT";
else if ("2mm" == band) result = "241G";
else if ("2.5mm" == band) result = "134G";
@ -124,12 +174,15 @@ QString CabrilloLog::impl::cabrillo_frequency_string (Radio::Frequency frequency
else if ("2m" == band) result = "144";
else if ("4m" == band) result = "70";
else if ("6m" == band) result = "50";
else result = QString::number (frequency);
else result = QString::number (frequency / 1000ull);
return result;
}
CabrilloLog::CabrilloLog (Configuration const * configuration)
: m_ {configuration}
#include "moc_CabrilloLog.cpp"
CabrilloLog::CabrilloLog (Configuration const * configuration, QObject * parent)
: QObject {parent}
, m_ {this, configuration}
{
Q_ASSERT (configuration);
}
@ -158,11 +211,12 @@ namespace
}
}
bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call
bool CabrilloLog::add_QSO (Frequency frequency, QString const& mode, QDateTime const& when, QString const& call
, QString const& exchange_sent, QString const& exchange_received)
{
auto record = m_->record ();
record.setValue ("frequency", frequency / 1000ull); // kHz
record.setValue ("frequency", frequency);
record.setValue ("mode", mode);
if (!when.isNull ())
{
record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull);
@ -174,15 +228,16 @@ bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString c
set_value_maybe_null (record, "call", call);
set_value_maybe_null (record, "exchange_sent", exchange_sent);
set_value_maybe_null (record, "exchange_rcvd", exchange_received);
set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency));
if (m_->isDirty ())
{
m_->revert (); // discard any uncommitted changes
}
m_->setEditStrategy (QSqlTableModel::OnManualSubmit);
ConditionalTransaction transaction {*m_};
m_->adding_row_ = true;
auto ok = m_->insertRecord (-1, record);
transaction.submit ();
m_->adding_row_ = false;
m_->setEditStrategy (QSqlTableModel::OnFieldChange);
return ok;
}
@ -190,10 +245,18 @@ bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString c
bool CabrilloLog::dupe (Frequency frequency, QString const& call) const
{
m_->dupe_query_.bindValue (":call", call);
m_->dupe_query_.bindValue (":band", m_->configuration_->bands ()->find (frequency));
SQL_error_check (m_->dupe_query_, static_cast<bool (QSqlQuery::*) ()> (&QSqlQuery::exec));
m_->dupe_query_.next ();
return m_->dupe_query_.value (0).toInt ();
auto record = m_->dupe_query_.record ();
auto frequency_index = record.indexOf ("frequency");
while (m_->dupe_query_.next ())
{
if (m_->configuration_->bands ()->find (m_->dupe_query_.value (frequency_index).toULongLong ())
== m_->configuration_->bands ()->find (frequency))
{
return true;
}
}
return false;
}
void CabrilloLog::reset ()
@ -208,6 +271,7 @@ void CabrilloLog::reset ()
transaction.submit ();
m_->select (); // to refresh views
m_->setEditStrategy (QSqlTableModel::OnFieldChange);
Q_EMIT data_changed ();
}
}
@ -216,6 +280,7 @@ void CabrilloLog::export_qsos (QTextStream& stream) const
SQL_error_check (m_->export_query_, static_cast<bool (QSqlQuery::*) ()> (&QSqlQuery::exec));
auto record = m_->export_query_.record ();
auto frequency_index = record.indexOf ("frequency");
// auto mode_index = record.indexOf ("mode");
auto when_index = record.indexOf ("when");
auto call_index = record.indexOf ("call");
auto sent_index = record.indexOf ("exchange_sent");
@ -232,3 +297,17 @@ void CabrilloLog::export_qsos (QTextStream& stream) const
.arg (m_->export_query_.value (rcvd_index).toString (), -13);
}
}
auto CabrilloLog::unique_DXCC_entities (AD1CCty const * countries) const -> worked_set
{
QSqlQuery q {"SELECT DISTINCT BAND, CALL FROM cabrillo_log_v2"};
auto band_index = q.record ().indexOf ("band");
auto call_index = q.record ().indexOf ("call");
worked_set entities;
while (q.next ())
{
entities << worked_item {q.value (band_index).toString ()
, countries->lookup (q.value (call_index).toString ()).primary_prefix};
}
return entities;
}

View File

@ -1,33 +1,43 @@
#ifndef CABRILLO_LOG_HPP_
#define CABRILLO_LOG_HPP_
#include <boost/core/noncopyable.hpp>
#include <QObject>
#include <QSet>
#include <QPair>
#include <QString>
#include "Radio.hpp"
#include "pimpl_h.hpp"
class Configuration;
class QDateTime;
class QString;
class QSqlTableModel;
class QTextStream;
class AD1CCty;
class CabrilloLog final
: private boost::noncopyable
: public QObject
{
Q_OBJECT
public:
using Frequency = Radio::Frequency;
using worked_item = QPair<QString, QString>;
using worked_set = QSet<worked_item>;
explicit CabrilloLog (Configuration const *);
explicit CabrilloLog (Configuration const *, QObject * parent = nullptr);
~CabrilloLog ();
// returns false if insert fails
bool add_QSO (Frequency, QDateTime const&, QString const& call
bool add_QSO (Frequency, QString const& mode, QDateTime const&, QString const& call
, QString const& report_sent, QString const& report_received);
bool dupe (Frequency, QString const& call) const;
QSqlTableModel * model ();
void reset ();
void export_qsos (QTextStream&) const;
worked_set unique_DXCC_entities (AD1CCty const *) const;
Q_SIGNAL void data_changed () const;
private:
class impl;

View File

@ -127,7 +127,9 @@ namespace
{7074000, Modes::FT8, IARURegions::ALL},
{7076000, Modes::JT65, IARURegions::ALL},
{7078000, Modes::JT9, IARURegions::ALL},
{7047000, Modes::FT4, IARURegions::ALL}, // provisional
{7047500, Modes::FT4, IARURegions::ALL}, // provisional - moved
// up 500Hz to clear
// W1AW code practice QRG
// Band plans (all USB dial unless stated otherwise)
//

View File

@ -6,6 +6,7 @@
#include <QString>
#include <QSqlError>
#include <QSqlTableModel>
#include "boost/core/noncopyable.hpp"
template<typename T, typename Func, typename... Args>
void SQL_error_check (T&& object, Func func, Args&&... args)

View File

@ -1,5 +1,5 @@
set (SAMPLE_FILES
FT4/190106_000112.wav
FT4/000000_000002.wav
FT8/181201_180245.wav
ISCAT/ISCAT-A/VK7MO_110401_235515.wav
ISCAT/ISCAT-B/K0AWU_100714_115000.wav

View File

@ -1,10 +1,12 @@
#include "CabrilloLogWindow.hpp"
#include <stdexcept>
#include <QApplication>
#include <QIdentityProxyModel>
#include <QSqlTableModel>
#include "Configuration.hpp"
#include "models/Bands.hpp"
#include "item_delegates/FrequencyDelegate.hpp"
#include "item_delegates/ForeignKeyDelegate.hpp"
#include "item_delegates/CallsignDelegate.hpp"
#include "pimpl_impl.hpp"
@ -29,7 +31,7 @@ namespace
switch (index.column ())
{
case 1:
case 6:
case 7:
return Qt::AlignRight + Qt::AlignVCenter;
default:
break;
@ -63,10 +65,10 @@ CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const
m_->format_model_.setSourceModel (m_->log_model_);
m_->ui_.log_table_view->setModel (&m_->format_model_);
set_log_view (m_->ui_.log_table_view);
m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this});
m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), 0, this});
m_->ui_.log_table_view->setItemDelegateForColumn (1, new FrequencyDelegate {this});
m_->ui_.log_table_view->setItemDelegateForColumn (4, new CallsignDelegate {this});
auto h_header = m_->ui_.log_table_view->horizontalHeader ();
h_header->moveSection (6, 1); // band to first column
h_header->moveSection (7, 1); // band to first column
}
CabrilloLogWindow::~CabrilloLogWindow ()

View File

@ -0,0 +1,54 @@
#include "FrequencyDeltaLineEdit.hpp"
#include <limits>
#include <QDoubleValidator>
#include <QString>
#include <QLocale>
#include "moc_FrequencyDeltaLineEdit.cpp"
namespace
{
class MHzValidator
: public QDoubleValidator
{
public:
MHzValidator (double bottom, double top, QObject * parent = nullptr)
: QDoubleValidator {bottom, top, 6, parent}
{
}
State validate (QString& input, int& pos) const override
{
State result = QDoubleValidator::validate (input, pos);
if (Acceptable == result)
{
bool ok;
(void)QLocale {}.toDouble (input, &ok);
if (!ok)
{
result = Intermediate;
}
}
return result;
}
};
}
FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent)
: QLineEdit (parent)
{
setValidator (new MHzValidator {-std::numeric_limits<FrequencyDelta>::max () / 10.e6,
std::numeric_limits<FrequencyDelta>::max () / 10.e6, this});
}
auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta
{
return Radio::frequency_delta (text (), 6);
}
void FrequencyDeltaLineEdit::frequency_delta (FrequencyDelta d)
{
setText (Radio::frequency_MHz_string (d));
}

View File

@ -0,0 +1,29 @@
#ifndef FREQUENCY_DELTA_LINE_EDIT_HPP_
#define FREQUENCY_DELTA_LINE_EDIT_HPP_
#include <QLineEdit>
#include "Radio.hpp"
class QWidget;
//
// MHz frequency delta line edit with validation
//
class FrequencyDeltaLineEdit final
: public QLineEdit
{
Q_OBJECT;
Q_PROPERTY (FrequencyDelta frequency_delta READ frequency_delta WRITE frequency_delta USER true);
public:
using FrequencyDelta = Radio::FrequencyDelta;
explicit FrequencyDeltaLineEdit (QWidget * parent = nullptr);
// Property frequency_delta implementation
FrequencyDelta frequency_delta () const;
void frequency_delta (FrequencyDelta);
};
#endif

View File

@ -51,21 +51,3 @@ void FrequencyLineEdit::frequency (Frequency f)
{
setText (Radio::frequency_MHz_string (f));
}
FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent)
: QLineEdit (parent)
{
setValidator (new MHzValidator {-std::numeric_limits<FrequencyDelta>::max () / 10.e6,
std::numeric_limits<FrequencyDelta>::max () / 10.e6, this});
}
auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta
{
return Radio::frequency_delta (text (), 6);
}
void FrequencyDeltaLineEdit::frequency_delta (FrequencyDelta d)
{
setText (Radio::frequency_MHz_string (d));
}

View File

@ -8,7 +8,7 @@
class QWidget;
//
// MHz frequency line edits with validation
// MHz frequency line edit with validation
//
class FrequencyLineEdit final
: public QLineEdit
@ -26,20 +26,4 @@ public:
void frequency (Frequency);
};
class FrequencyDeltaLineEdit final
: public QLineEdit
{
Q_OBJECT;
Q_PROPERTY (FrequencyDelta frequency_delta READ frequency_delta WRITE frequency_delta USER true);
public:
using FrequencyDelta = Radio::FrequencyDelta;
explicit FrequencyDeltaLineEdit (QWidget * parent = nullptr);
// Property frequency_delta implementation
FrequencyDelta frequency_delta () const;
void frequency_delta (FrequencyDelta);
};
#endif

View File

@ -271,7 +271,7 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons
if(call.length()<3) return message;
if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return message;
auto const& looked_up = logBook.countries ().lookup (call);
auto const& looked_up = logBook.countries ()->lookup (call);
logBook.match (call, currentMode, grid, looked_up, callB4, countryB4, gridB4, continentB4, CQZoneB4, ITUZoneB4);
logBook.match (call, currentMode, grid, looked_up, callB4onBand, countryB4onBand, gridB4onBand,
continentB4onBand, CQZoneB4onBand, ITUZoneB4onBand, currentBand);

View File

@ -65,6 +65,4 @@ private:
int modified_vertical_scrollbar_max_;
};
extern QHash<QString,int> m_LoTW;
#endif // DISPLAYTEXT_H

View File

@ -16,11 +16,12 @@
#include "moc_logqso.cpp"
LogQSO::LogQSO(QString const& programTitle, QSettings * settings
, Configuration const * config, QWidget *parent)
, Configuration const * config, LogBook * log, QWidget *parent)
: QDialog {parent, Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint}
, ui(new Ui::LogQSO)
, m_settings (settings)
, m_config {config}
, m_log {log}
{
ui->setupUi(this);
setWindowTitle(programTitle + " - Log QSO");
@ -57,8 +58,7 @@ void LogQSO::storeSettings () const
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, bool noSuffix, QString xSent, QString xRcvd,
CabrilloLog * cabrillo_log)
Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd)
{
if(!isHidden()) return;
ui->call->setText (hisCall);
@ -100,7 +100,6 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
ui->loggedOperator->setText(m_config->opCall());
ui->exchSent->setText (xSent);
ui->exchRcvd->setText (xRcvd);
m_cabrilloLog = cabrillo_log;
using SpOp = Configuration::SpecialOperatingActivity;
auto special_op = m_config->special_op_id ();
@ -158,7 +157,7 @@ void LogQSO::accept()
return; // without accepting
}
if (!m_cabrilloLog->add_QSO (m_dialFreq, dateTimeOff, hisCall, xsent, xrcvd))
if (!m_log->contest_log ()->add_QSO (m_dialFreq, mode, dateTimeOff, hisCall, xsent, xrcvd))
{
show ();
MessageBox::warning_message (this, tr ("Invalid QSO Data"),

View File

@ -17,19 +17,19 @@ namespace Ui {
class QSettings;
class Configuration;
class QByteArray;
class CabrilloLog;
class LogBook;
class LogQSO : public QDialog
{
Q_OBJECT
public:
explicit LogQSO(QString const& programTitle, QSettings *, Configuration const *, QWidget *parent = 0);
explicit LogQSO(QString const& programTitle, QSettings *, Configuration const *, LogBook *, QWidget *parent = 0);
~LogQSO();
void initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode,
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff, Radio::Frequency dialFreq,
bool noSuffix, QString xSent, QString xRcvd, CabrilloLog *);
bool noSuffix, QString xSent, QString xRcvd);
public slots:
void accept();
@ -54,12 +54,12 @@ private:
QScopedPointer<Ui::LogQSO> ui;
QSettings * m_settings;
Configuration const * m_config;
LogBook * m_log;
QString m_txPower;
QString m_comments;
Radio::Frequency m_dialFreq;
QString m_myCall;
QString m_myGrid;
CabrilloLog * m_cabrilloLog;
};
#endif // LogQSO_H

View File

@ -244,7 +244,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_echoGraph (new EchoGraph(m_settings)),
m_fastGraph (new FastGraph(m_settings)),
// no parent so that it has a taskbar icon
m_logDlg (new LogQSO (program_title (), m_settings, &m_config, nullptr)),
m_logDlg (new LogQSO (program_title (), m_settings, &m_config, &m_logBook, nullptr)),
m_lastDialFreq {0},
m_dialFreqRxWSPR {0},
m_detector {new Detector {RX_SAMPLE_RATE, double(NTMAX), downSampleFactor}},
@ -2544,16 +2544,14 @@ void MainWindow::on_actionAstronomical_data_toggled (bool checked)
void MainWindow::on_fox_log_action_triggered()
{
if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config});
if (!m_foxLogWindow)
{
m_foxLogWindow.reset (new FoxLogWindow {m_settings, &m_config, m_foxLog.data ()});
m_foxLogWindow.reset (new FoxLogWindow {m_settings, &m_config, m_logBook.fox_log ()});
// Connect signals from fox log window
connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close);
connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () {
if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config});
m_foxLog->reset ();
m_logBook.fox_log ()->reset ();
});
}
m_foxLogWindow->showNormal ();
@ -2563,10 +2561,9 @@ void MainWindow::on_fox_log_action_triggered()
void MainWindow::on_contest_log_action_triggered()
{
if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
if (!m_contestLogWindow)
{
m_contestLogWindow.reset (new CabrilloLogWindow {m_settings, &m_config, m_cabrilloLog->model ()});
m_contestLogWindow.reset (new CabrilloLogWindow {m_settings, &m_config, m_logBook.contest_log ()->model ()});
// Connect signals from contest log window
connect (this, &MainWindow::finished, m_contestLogWindow.data (), &CabrilloLogWindow::close);
@ -5521,15 +5518,9 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button
default: break;
}
auto special_op = m_config.special_op_id ();
if (SpecOp::NONE < special_op && special_op < SpecOp::FOX)
{
if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
}
m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd,
m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal +
ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd,
m_cabrilloLog.data ());
ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd);
m_inQSOwith="";
}
@ -6369,15 +6360,13 @@ void MainWindow::on_reset_cabrillo_log_action_triggered ()
"for export in your Cabrillo log.")))
{
if(m_config.RTTY_Exchange()!="SCC") ui->sbSerialNumber->setValue(1);
if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
m_cabrilloLog->reset ();
m_logBook.contest_log ()->reset ();
}
}
void MainWindow::on_actionExport_Cabrillo_log_triggered()
{
if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
if (QDialog::Accepted == ExportCabrillo {m_settings, &m_config, m_cabrilloLog.data ()}.exec())
if (QDialog::Accepted == ExportCabrillo {m_settings, &m_config, m_logBook.contest_log ()}.exec())
{
MessageBox::information_message (this, tr ("Cabrillo Log saved"));
}
@ -8278,7 +8267,7 @@ void MainWindow::houndCallers()
if(!ui->textBrowser4->toPlainText().contains(paddedHoundCall)) {
if(m_loggedByFox[houndCall].contains(m_lastBand)) continue; //already logged on this band
if(m_foxQSO.contains(houndCall)) continue; //still in the QSO map
auto const& entity = m_logBook.countries ().lookup (houndCall);
auto const& entity = m_logBook.countries ()->lookup (houndCall);
auto const& continent = AD1CCty::continent (entity.continent);
//If we are using a directed CQ, ignore Hound calls that do not comply.
@ -8459,9 +8448,8 @@ list2Done:
m_hisGrid=m_foxQSO[hc1].grid;
m_rptSent=m_foxQSO[hc1].sent;
m_rptRcvd=m_foxQSO[hc1].rcvd;
if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config});
if (!m_foxLogWindow) on_fox_log_action_triggered ();
if (m_foxLog->add_QSO (QSO_time, m_hisCall, m_hisGrid, m_rptSent, m_rptRcvd, m_lastBand))
if (m_logBook.fox_log ()->add_QSO (QSO_time, m_hisCall, m_hisGrid, m_rptSent, m_rptRcvd, m_lastBand))
{
writeFoxQSO (QString {" Log: %1 %2 %3 %4 %5"}.arg (m_hisCall).arg (m_hisGrid)
.arg (m_rptSent).arg (m_rptRcvd).arg (m_lastBand));

View File

@ -72,9 +72,7 @@ class WideGraph;
class LogQSO;
class Transceiver;
class MessageAveraging;
class FoxLog;
class FoxLogWindow;
class CabrilloLog;
class CabrilloLogWindow;
class ColorHighlighting;
class MessageClient;
@ -376,9 +374,7 @@ private:
QScopedPointer<HelpTextWindow> m_prefixes;
QScopedPointer<HelpTextWindow> m_mouseCmnds;
QScopedPointer<MessageAveraging> m_msgAvgWidget;
QScopedPointer<FoxLog> m_foxLog;
QScopedPointer<FoxLogWindow> m_foxLogWindow;
QScopedPointer<CabrilloLog> m_cabrilloLog;
QScopedPointer<CabrilloLogWindow> m_contestLogWindow;
QScopedPointer<ColorHighlighting> m_colorHighlighting;
Transceiver::TransceiverState m_rigState;

View File

@ -8,13 +8,14 @@ SOURCES += \
widgets/fastplot.cpp widgets/MessageBox.cpp \
widgets/colorhighlighting.cpp widgets/ExportCabrillo.cpp \
widgets/AbstractLogWindow.cpp \
widgets/FrequencyLineEdit.cpp widgets/FrequencyDeltaLineEdit.cpp \
widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp
HEADERS += \
widgets/mainwindow.h widgets/plotter.h \
widgets/about.h widgets/widegraph.h \
widgets/displaytext.h widgets/logqso.h widgets/LettersSpinBox.hpp \
widgets/FrequencyLineEdit.hpp widgets/signalmeter.h \
widgets/FrequencyLineEdit.hpp widgets/FrequencyDeltaLineEdit.hpp widgets/signalmeter.h \
widgets/meterwidget.h widgets/messageaveraging.h \
widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \
widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \