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

View File

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

View File

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

View File

@ -2294,6 +2294,23 @@ Right click for insert and delete options.</string>
</item> </item>
</layout> </layout>
</item> </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> </layout>
</widget> </widget>
</item> </item>
@ -2306,35 +2323,6 @@ Right click for insert and delete options.</string>
<string>Logbook of the World User Validation</string> <string>Logbook of the World User Validation</string>
</property> </property>
<layout class="QFormLayout" name="formLayout_18"> <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"> <item row="1" column="0">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="label_15">
<property name="text"> <property name="text">
@ -2369,6 +2357,35 @@ Right click for insert and delete options.</string>
</item> </item>
</layout> </layout>
</item> </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> </layout>
</widget> </widget>
</item> </item>
@ -3085,13 +3102,13 @@ Right click for insert and delete options.</string>
</connection> </connection>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="split_mode_button_group"/> <buttongroup name="special_op_activity_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/> <buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="CAT_handshake_button_group"/> <buttongroup name="split_mode_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="TX_mode_button_group"/> <buttongroup name="TX_mode_button_group"/>
<buttongroup name="PTT_method_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_stop_bits_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
</buttongroups> </buttongroups>
</ui> </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}; throw error {tr ("DX Lab Suite Commander didn't respond correctly reading frequency: ") + reply};
} }
poll (); do_poll ();
return resolution; return resolution;
} }
@ -247,7 +247,7 @@ void DXLabSuiteCommanderTransceiver::do_mode (MODE m)
update_mode (m); update_mode (m);
} }
void DXLabSuiteCommanderTransceiver::poll () void DXLabSuiteCommanderTransceiver::do_poll ()
{ {
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
bool quiet {false}; bool quiet {false};

View File

@ -39,7 +39,7 @@ protected:
void do_mode (MODE) override; void do_mode (MODE) override;
void do_ptt (bool on) override; void do_ptt (bool on) override;
void poll () override; void do_poll () override;
private: private:
MODE get_mode (bool no_debug = false); 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; return "1" == reply;
} }
void HRDTransceiver::poll () void HRDTransceiver::do_poll ()
{ {
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
bool quiet {false}; bool quiet {false};

View File

@ -48,7 +48,7 @@ protected:
void do_ptt (bool on) override; void do_ptt (bool on) override;
// Implement the PollingTransceiver interface. // Implement the PollingTransceiver interface.
void poll () override; void do_poll () override;
private: private:
QString send_command (QString const&, bool no_debug = false, bool prepend_context = true, bool recurse = false); 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 resolution = -1; // best guess
} }
poll (); do_poll ();
TRACE_CAT ("HamlibTransceiver", "exit" << state () << "reversed =" << reversed_ << "resolution = " << resolution); TRACE_CAT ("HamlibTransceiver", "exit" << state () << "reversed =" << reversed_ << "resolution = " << resolution);
return resolution; return resolution;
@ -898,7 +898,7 @@ void HamlibTransceiver::do_mode (MODE mode)
update_mode (mode); update_mode (mode);
} }
void HamlibTransceiver::poll () void HamlibTransceiver::do_poll ()
{ {
#if !WSJT_TRACE_CAT_POLLS #if !WSJT_TRACE_CAT_POLLS
#if defined (NDEBUG) #if defined (NDEBUG)

View File

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

View File

@ -14,17 +14,35 @@
#include "WFPalette.hpp" #include "WFPalette.hpp"
#include "models/IARURegions.hpp" #include "models/IARURegions.hpp"
#include "models/DecodeHighlightingModel.hpp" #include "models/DecodeHighlightingModel.hpp"
#include "widgets/FrequencyLineEdit.hpp"
#include "widgets/DateTimeEdit.hpp" #include "widgets/DateTimeEdit.hpp"
QItemEditorFactory * item_editor_factory () namespace
{ {
static QItemEditorFactory * our_item_editor_factory = new QItemEditorFactory; class ItemEditorFactory final
return our_item_editor_factory; : 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 () 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 // types in Radio.hpp are registered in their own translation unit
// as they are needed in the wsjtx_udp shared library too // 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 // used as signal/slot connection arguments since the new Qt 5.5
// Q_ENUM macro only seems to register the unqualified name // Q_ENUM macro only seems to register the unqualified name
item_editor_factory ()->registerEditor (qMetaTypeId<Radio::Frequency> (), new QStandardItemEditorCreator<FrequencyLineEdit> ()); item_editor_factory->registerEditor (qMetaTypeId<QDateTime> (), new QStandardItemEditorCreator<DateTimeEdit> ());
//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);
// Frequency list model // Frequency list model
qRegisterMetaTypeStreamOperators<FrequencyList_v2::Item> ("Item_v2"); qRegisterMetaTypeStreamOperators<FrequencyList_v2::Item> ("Item_v2");

View File

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

View File

@ -4,6 +4,7 @@
#include <QDebug> #include <QDebug>
#include <objbase.h> #include <objbase.h>
#include <QThread> #include <QThread>
#include <QEventLoop>
#include "qt_helpers.hpP" #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 () int OmniRigTransceiver::do_start ()
{ {
TRACE_CAT ("OmniRigTransceiver", "starting"); TRACE_CAT ("OmniRigTransceiver", "starting");
@ -182,19 +192,14 @@ int OmniRigTransceiver::do_start ()
.arg (readable_params_, 8, 16, QChar ('0')) .arg (readable_params_, 8, 16, QChar ('0'))
.arg (writable_params_, 8, 16, QChar ('0')) .arg (writable_params_, 8, 16, QChar ('0'))
.arg (rig_number_).toLocal8Bit ()); .arg (rig_number_).toLocal8Bit ());
if (OmniRig::ST_ONLINE != rig_->Status ())
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)
{ {
QThread::msleep (100); // wait until OmniRig polls the rig throw_qstring ("OmniRig: " + rig_->StatusStr ());
auto f = rig_->GetRxFrequency (); }
await_notification_with_timeout (1000);
update_rx_frequency (rig_->GetRxFrequency ());
qDebug () << "Initial state:" << state ();
int resolution {0}; int resolution {0};
if (f)
{
if (OmniRig::PM_UNKNOWN == rig_->Vfo () if (OmniRig::PM_UNKNOWN == rig_->Vfo ()
&& (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB)) && (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
== (OmniRig::PM_VFOA | OmniRig::PM_VFOB)) == (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
@ -203,6 +208,7 @@ int OmniRigTransceiver::do_start ()
// can't query VFO but can set explicitly // can't query VFO but can set explicitly
rig_->SetVfo (OmniRig::PM_VFOA); rig_->SetVfo (OmniRig::PM_VFOA);
} }
auto f = state ().frequency ();
if (f % 10) return resolution; // 1Hz resolution if (f % 10) return resolution; // 1Hz resolution
auto test_frequency = f - f % 100 + 55; auto test_frequency = f - f % 100 + 55;
if (OmniRig::PM_FREQ & writable_params_) if (OmniRig::PM_FREQ & writable_params_)
@ -221,6 +227,11 @@ int OmniRigTransceiver::do_start ()
{ {
throw_qstring (tr ("OmniRig: don't know how to set rig frequency")); 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) switch (rig_->GetRxFrequency () - test_frequency)
{ {
case -5: resolution = -1; break; // 10Hz truncated case -5: resolution = -1; break; // 10Hz truncated
@ -244,6 +255,11 @@ int OmniRigTransceiver::do_start ()
{ {
rig_->SetFreqA (test_frequency); 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) if (9 == rig_->GetRxFrequency () - test_frequency)
{ {
resolution = 2; // 20Hz rounded resolution = 2; // 20Hz rounded
@ -264,19 +280,9 @@ int OmniRigTransceiver::do_start ()
update_rx_frequency (f); update_rx_frequency (f);
return resolution; return resolution;
} }
}
throw_qstring (tr ("OmniRig: Initialization timed out"));
return 0; // keep compiler happy
}
void OmniRigTransceiver::do_stop () void OmniRigTransceiver::do_stop ()
{ {
if (offline_timer_)
{
offline_timer_->stop ();
offline_timer_.reset ();
}
QThread::msleep (200); // leave some time for pending QThread::msleep (200); // leave some time for pending
// commands at the server end // commands at the server end
if (port_) if (port_)
@ -300,17 +306,6 @@ void OmniRigTransceiver::do_stop ()
TRACE_CAT ("OmniRigTransceiver", "stopped"); 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) void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help)
{ {
TRACE_CAT ("OmniRigTransceiver", QString::number (code) + " at " + source + ": " + desc + " (" + 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 () void OmniRigTransceiver::handle_visible_change ()
{ {
if (!omni_rig_ || omni_rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ()); TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ());
} }
void OmniRigTransceiver::handle_rig_type_change (int rig_number) 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_number_ == rig_number)
{ {
if (!rig_ || rig_->isNull ()) return;
readable_params_ = rig_->ReadableParams (); readable_params_ = rig_->ReadableParams ();
writable_params_ = rig_->WriteableParams (); 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 (rig_->RigType ())
.arg (readable_params_, 8, 16, QChar ('0')) .arg (readable_params_, 8, 16, QChar ('0'))
.arg (writable_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) 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_number_ == rig_number)
{ {
if (!rig_ || rig_->isNull ()) return;
auto const& status = rig_->StatusStr ().toLocal8Bit (); 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 (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 ());
}
}
}
void OmniRigTransceiver::timeout_check ()
{ {
offline ("Rig went offline"); offline ("Rig went offline");
} }
// else
// {
// update_rx_frequency (rig_->GetRxFrequency ());
// update_complete ();
// TRACE_CAT ("OmniRigTransceiver", "frequency:" << state ().frequency ());
// }
}
}
void OmniRigTransceiver::handle_params_change (int rig_number, int params) void OmniRigTransceiver::handle_params_change (int rig_number, int params)
{ {
if (rig_number_ == rig_number) if (!omni_rig_ || omni_rig_->isNull ()) return;
{ TRACE_CAT ("OmniRigTransceiver", QString {"params change: params = 0x%1 for rig %2"}
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig params change: params = 0x%1 for rig %2"}
.arg (params, 8, 16, QChar ('0')) .arg (params, 8, 16, QChar ('0'))
.arg (rig_number).toLocal8Bit () .arg (rig_number).toLocal8Bit ()
<< "state before:" << state ()); << "state before:" << state ());
if (rig_number_ == rig_number)
{
if (!rig_ || rig_->isNull ()) return;
// starting_ = false; // starting_ = false;
TransceiverState old_state {state ()}; TransceiverState old_state {state ()};
auto need_frequency = false; 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) if (params & OmniRig::PM_VFOAA)
{ {
TRACE_CAT ("OmniRigTransceiver", "VFOAA");
update_split (false); update_split (false);
reversed_ = false; reversed_ = false;
update_rx_frequency (rig_->FreqA ()); update_rx_frequency (rig_->FreqA ());
@ -387,6 +381,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
} }
if (params & OmniRig::PM_VFOAB) if (params & OmniRig::PM_VFOAB)
{ {
TRACE_CAT ("OmniRigTransceiver", "VFOAB");
update_split (true); update_split (true);
reversed_ = false; reversed_ = false;
update_rx_frequency (rig_->FreqA ()); update_rx_frequency (rig_->FreqA ());
@ -394,6 +389,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
} }
if (params & OmniRig::PM_VFOBA) if (params & OmniRig::PM_VFOBA)
{ {
TRACE_CAT ("OmniRigTransceiver", "VFOBA");
update_split (true); update_split (true);
reversed_ = true; reversed_ = true;
update_other_frequency (rig_->FreqA ()); update_other_frequency (rig_->FreqA ());
@ -401,6 +397,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
} }
if (params & OmniRig::PM_VFOBB) if (params & OmniRig::PM_VFOBB)
{ {
TRACE_CAT ("OmniRigTransceiver", "VFOBB");
update_split (false); update_split (false);
reversed_ = true; reversed_ = true;
update_other_frequency (rig_->FreqA ()); update_other_frequency (rig_->FreqA ());
@ -408,64 +405,75 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
} }
if (params & OmniRig::PM_VFOA) if (params & OmniRig::PM_VFOA)
{ {
TRACE_CAT ("OmniRigTransceiver", "VFOA");
reversed_ = false; reversed_ = false;
need_frequency = true; need_frequency = true;
} }
if (params & OmniRig::PM_VFOB) if (params & OmniRig::PM_VFOB)
{ {
TRACE_CAT ("OmniRigTransceiver", "VFOB");
reversed_ = true; reversed_ = true;
need_frequency = true; need_frequency = true;
} }
if (params & OmniRig::PM_FREQ) if (params & OmniRig::PM_FREQ)
{ {
TRACE_CAT ("OmniRigTransceiver", "FREQ");
need_frequency = true; need_frequency = true;
} }
if (params & OmniRig::PM_FREQA) if (params & OmniRig::PM_FREQA)
{ {
auto f = rig_->FreqA ();
TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f);
if (reversed_) if (reversed_)
{ {
update_other_frequency (rig_->FreqA ()); update_other_frequency (f);
} }
else else
{ {
update_rx_frequency (rig_->FreqA ()); update_rx_frequency (f);
} }
} }
if (params & OmniRig::PM_FREQB) if (params & OmniRig::PM_FREQB)
{ {
auto f = rig_->FreqB ();
TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f);
if (reversed_) if (reversed_)
{ {
update_rx_frequency (rig_->FreqB ()); update_rx_frequency (f);
} }
else else
{ {
update_other_frequency (rig_->FreqB ()); update_other_frequency (f);
} }
} }
if (need_frequency) if (need_frequency)
{ {
if (readable_params_ & OmniRig::PM_FREQA) if (readable_params_ & OmniRig::PM_FREQA)
{ {
auto f = rig_->FreqA ();
TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f);
if (reversed_) if (reversed_)
{ {
update_other_frequency (rig_->FreqA ()); update_other_frequency (f);
} }
else else
{ {
update_rx_frequency (rig_->FreqA ()); update_rx_frequency (f);
} }
need_frequency = false; need_frequency = false;
} }
if (readable_params_ & OmniRig::PM_FREQB) if (readable_params_ & OmniRig::PM_FREQB)
{ {
auto f = rig_->FreqB ();
TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f);
if (reversed_) if (reversed_)
{ {
update_rx_frequency (rig_->FreqB ()); update_rx_frequency (f);
} }
else else
{ {
update_other_frequency (rig_->FreqB ()); update_other_frequency (f);
} }
need_frequency = false; 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) if (need_frequency && (readable_params_ & OmniRig::PM_FREQ)
&& !state ().ptt ()) && !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) if (params & OmniRig::PM_PITCH)
{ {
TRACE_CAT ("OmniRigTransceiver", "PITCH");
} }
if (params & OmniRig::PM_RITOFFSET) if (params & OmniRig::PM_RITOFFSET)
{ {
TRACE_CAT ("OmniRigTransceiver", "RITOFFSET");
} }
if (params & OmniRig::PM_RIT0) if (params & OmniRig::PM_RIT0)
{ {
TRACE_CAT ("OmniRigTransceiver", "RIT0");
} }
if (params & OmniRig::PM_VFOEQUAL) if (params & OmniRig::PM_VFOEQUAL)
{ {
auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq (); 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_rx_frequency (f);
update_other_frequency (f); update_other_frequency (f);
update_mode (map_mode (rig_->Mode ())); update_mode (m);
} }
if (params & OmniRig::PM_VFOSWAP) 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_other_frequency (state ().frequency ());
update_rx_frequency (temp); update_rx_frequency (f);
update_mode (map_mode (rig_->Mode ())); update_mode (map_mode (rig_->Mode ()));
} }
if (params & OmniRig::PM_SPLITON) if (params & OmniRig::PM_SPLITON)
{ {
TRACE_CAT ("OmniRigTransceiver", "SPLITON");
update_split (true); update_split (true);
} }
if (params & OmniRig::PM_SPLITOFF) if (params & OmniRig::PM_SPLITOFF)
{ {
TRACE_CAT ("OmniRigTransceiver", "SPLITOFF");
update_split (false); update_split (false);
} }
if (params & OmniRig::PM_RITON) if (params & OmniRig::PM_RITON)
{ {
TRACE_CAT ("OmniRigTransceiver", "RITON");
} }
if (params & OmniRig::PM_RITOFF) if (params & OmniRig::PM_RITOFF)
{ {
TRACE_CAT ("OmniRigTransceiver", "RITOFF");
} }
if (params & OmniRig::PM_XITON) if (params & OmniRig::PM_XITON)
{ {
TRACE_CAT ("OmniRigTransceiver", "XITON");
} }
if (params & OmniRig::PM_XITOFF) if (params & OmniRig::PM_XITOFF)
{ {
TRACE_CAT ("OmniRigTransceiver", "XITOFF");
} }
if (params & OmniRig::PM_RX) if (params & OmniRig::PM_RX)
{ {
TRACE_CAT ("OmniRigTransceiver", "RX");
update_PTT (false); update_PTT (false);
} }
if (params & OmniRig::PM_TX) if (params & OmniRig::PM_TX)
{ {
TRACE_CAT ("OmniRigTransceiver", "TX");
update_PTT (); update_PTT ();
} }
if (params & OmniRig::PM_CW_U) if (params & OmniRig::PM_CW_U)
{ {
TRACE_CAT ("OmniRigTransceiver", "CW-R");
update_mode (CW_R); update_mode (CW_R);
} }
if (params & OmniRig::PM_CW_L) if (params & OmniRig::PM_CW_L)
{ {
TRACE_CAT ("OmniRigTransceiver", "CW");
update_mode (CW); update_mode (CW);
} }
if (params & OmniRig::PM_SSB_U) if (params & OmniRig::PM_SSB_U)
{ {
TRACE_CAT ("OmniRigTransceiver", "USB");
update_mode (USB); update_mode (USB);
} }
if (params & OmniRig::PM_SSB_L) if (params & OmniRig::PM_SSB_L)
{ {
TRACE_CAT ("OmniRigTransceiver", "LSB");
update_mode (LSB); update_mode (LSB);
} }
if (params & OmniRig::PM_DIG_U) if (params & OmniRig::PM_DIG_U)
{ {
TRACE_CAT ("OmniRigTransceiver", "DATA-U");
update_mode (DIG_U); update_mode (DIG_U);
} }
if (params & OmniRig::PM_DIG_L) if (params & OmniRig::PM_DIG_L)
{ {
TRACE_CAT ("OmniRigTransceiver", "DATA-L");
update_mode (DIG_L); update_mode (DIG_L);
} }
if (params & OmniRig::PM_AM) if (params & OmniRig::PM_AM)
{ {
TRACE_CAT ("OmniRigTransceiver", "AM");
update_mode (AM); update_mode (AM);
} }
if (params & OmniRig::PM_FM) if (params & OmniRig::PM_FM)
{ {
TRACE_CAT ("OmniRigTransceiver", "FM");
update_mode (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 ()); 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) 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)command;
(void)reply; (void)reply;
if (!omni_rig_ || omni_rig_->isNull ()) return;
if (rig_number_ == rig_number) if (rig_number_ == rig_number)
{ {
if (!rig_ || rig_->isNull ()) return;
TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit () TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit ()
<< "with reply" << reply.toString ().toLocal8Bit () << "with reply" << reply.toString ().toLocal8Bit ()
<< QString ("for rig %1").arg (rig_number).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_tx_frequency (Frequency, MODE, bool no_ignore) override;
void do_mode (MODE) override; void do_mode (MODE) override;
void do_ptt (bool on) override; void do_ptt (bool on) override;
void do_sync (bool force_signal, bool no_poll) override;
private: 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_COM_exception (int, QString, QString, QString);
Q_SLOT void handle_visible_change (); Q_SLOT void handle_visible_change ();
Q_SLOT void handle_rig_type_change (int rig_number); Q_SLOT void handle_rig_type_change (int rig_number);
@ -62,7 +63,7 @@ private:
QString rig_type_; QString rig_type_;
int readable_params_; int readable_params_;
int writable_params_; int writable_params_;
QScopedPointer<QTimer> offline_timer_; // QScopedPointer<QTimer> offline_timer_;
bool send_update_signal_; bool send_update_signal_;
bool reversed_; // some rigs can reverse VFOs bool reversed_; // some rigs can reverse VFOs
}; };

View File

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

View File

@ -39,11 +39,9 @@ protected:
QObject * parent); QObject * parent);
protected: 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 // Sub-classes implement this and fetch what they can from the rig
// in a non-intrusive manner. // in a non-intrusive manner.
virtual void poll () = 0; virtual void do_poll () = 0;
void do_post_start () override final; void do_post_start () override final;
void do_post_stop () 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) QString pretty_frequency_MHz_string (Frequency f, QLocale const& locale)

View File

@ -42,8 +42,8 @@ namespace Radio
// //
// Frequency type formatting // Frequency type formatting
// //
QString UDP_EXPORT frequency_MHz_string (Frequency, QLocale const& = QLocale ()); QString UDP_EXPORT frequency_MHz_string (Frequency, int precision = 6, QLocale const& = QLocale ());
QString UDP_EXPORT frequency_MHz_string (FrequencyDelta, 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 (Frequency, QLocale const& = QLocale ());
QString UDP_EXPORT pretty_frequency_MHz_string (double, int scale, 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 ()); 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 - N1MM Logger+ now uses the standard WSJT-X UDP messages
- OK/Cancel buttons on Log QSO window maintain fixed positions - OK/Cancel buttons on Log QSO window maintain fixed positions
- Put EU VHF contest serial numbers into the ADIF SRX and STX fields - 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 BUG FIXES
- Fix generation of Tx5 message when one callsign is nonstandard - 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 mode switch from FT4 to FT8
- Fix a bug that caused FT4 to do WSPR-style band hopping - Fix a bug that caused FT4 to do WSPR-style band hopping
- Fix a bug that caused a Fortran bounds error - 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 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 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; QString message;
try try
{ {
last_sequence_number_ = sequence_number;
may_update u {this, true}; may_update u {this, true};
shutdown (); shutdown ();
startup (); startup ();
last_sequence_number_ = sequence_number;
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {
@ -46,6 +46,7 @@ void TransceiverBase::set (TransceiverState const& s,
QString message; QString message;
try try
{ {
last_sequence_number_ = sequence_number;
may_update u {this, true}; may_update u {this, true};
bool was_online {requested_.online ()}; bool was_online {requested_.online ()};
if (!s.online () && was_online) if (!s.online () && was_online)
@ -115,7 +116,6 @@ void TransceiverBase::set (TransceiverState const& s,
// record what actually changed // record what actually changed
requested_.ptt (actual_.ptt ()); requested_.ptt (actual_.ptt ());
} }
last_sequence_number_ = sequence_number;
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {
@ -133,10 +133,27 @@ void TransceiverBase::set (TransceiverState const& s,
void TransceiverBase::startup () void TransceiverBase::startup ()
{ {
Q_EMIT resolution (do_start ()); QString message;
do_post_start (); try
{
actual_.online (true); actual_.online (true);
requested_.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 () void TransceiverBase::shutdown ()
@ -163,8 +180,8 @@ void TransceiverBase::shutdown ()
} }
do_stop (); do_stop ();
do_post_stop (); do_post_stop ();
actual_.online (false); actual_ = TransceiverState {};
requested_.online (false); requested_ = TransceiverState {};
} }
void TransceiverBase::stop () noexcept void TransceiverBase::stop () noexcept

View File

@ -112,8 +112,6 @@ protected:
virtual void do_ptt (bool = true) = 0; virtual void do_ptt (bool = true) = 0;
virtual void do_post_ptt (bool = true) {} 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;} virtual bool do_pre_update () {return true;}
// sub classes report rig state changes with these methods // sub classes report rig state changes with these methods

View File

@ -2,5 +2,5 @@
set (WSJTX_VERSION_MAJOR 2) set (WSJTX_VERSION_MAJOR 2)
set (WSJTX_VERSION_MINOR 1) set (WSJTX_VERSION_MINOR 1)
set (WSJTX_VERSION_PATCH 0) 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 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 += \ SOURCES += \
item_delegates/ForeignKeyDelegate.cpp \ item_delegates/ForeignKeyDelegate.cpp \
item_delegates/FrequencyItemDelegate.cpp \ item_delegates/FrequencyDelegate.cpp \
item_delegates/FrequencyDeltaDelegate.cpp \
item_delegates/CallsignDelegate.cpp \ item_delegates/CallsignDelegate.cpp \
item_delegates/MaidenheadLocatorItemDelegate.cpp item_delegates/MaidenheadLocatorItemDelegate.cpp
HEADERS += \ HEADERS += \
item_delegates/ForeignKeyDelegate.hpp \ item_delegates/ForeignKeyDelegate.hpp \
item_delegates/FrequencyItemDelegate.hpp \ item_delegates/FrequencyDelegate.hpp \
item_delegates/FrequencyDeltaDelegate.hpp \
item_delegates/CallsignDelegate.hpp \ item_delegates/CallsignDelegate.hpp \
item_delegates/MaidenheadLocatorDelegate.hpp item_delegates/MaidenheadLocatorDelegate.hpp

View File

@ -16,6 +16,7 @@
#include <QTextStream> #include <QTextStream>
#include <QDebug> #include <QDebug>
#include <QDebugStateSaver> #include <QDebugStateSaver>
#include "Configuration.hpp"
#include "Radio.hpp" #include "Radio.hpp"
#include "pimpl_impl.hpp" #include "pimpl_impl.hpp"
@ -155,14 +156,16 @@ typedef multi_index_container<
class AD1CCty::impl final class AD1CCty::impl final
{ {
public: 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 (); call = call.toUpper ();
using entity_by_id = entities_type::index<id>::type;
entity_by_id::iterator e; // iterator into entity set entity_by_id::iterator e; // iterator into entity set
// //
@ -171,23 +174,26 @@ public:
if (call.startsWith ("KG4") && call.size () != 5 && call.size () != 3) if (call.startsWith ("KG4") && call.size () != 5 && call.size () != 3)
{ {
// KG4 2x1 and 2x3 calls that map to Gitmo are mainland US not Gitmo // 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 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; Record result;
result.continent = e->continent_; result.continent = e.continent_;
result.CQ_zone = e->CQ_zone_; result.CQ_zone = e.CQ_zone_;
result.ITU_zone = e->ITU_zone_; result.ITU_zone = e.ITU_zone_;
result.entity_name = e->name_; result.entity_name = e.name_;
result.WAE_only = e->WAE_only_; result.WAE_only = e.WAE_only_;
result.latitude = e->lat_; result.latitude = e.lat_;
result.longtitude = e->long_; result.longtitude = e.long_;
result.UTC_offset = e->UTC_offset_; result.UTC_offset = e.UTC_offset_;
result.primary_prefix = e->primary_prefix_; result.primary_prefix = e.primary_prefix_;
// check for overrides // check for overrides
bool ok1 {true}, ok2 {true}, ok3 {true}, ok4 {true}, ok5 {true}; bool ok1 {true}, ok2 {true}, ok3 {true}, ok4 {true}, ok5 {true};
@ -220,6 +226,7 @@ public:
return false; return false;
} }
Configuration const * configuration_;
QString path_; QString path_;
entities_type entities_; entities_type entities_;
prefixes_type prefixes_; 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)}; QDir dataPath {QStandardPaths::writableLocation (QStandardPaths::DataLocation)};
m_->path_ = dataPath.exists (file_name) m_->path_ = dataPath.exists (file_name)
? dataPath.absoluteFilePath (file_name) // user override ? 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); auto p = m_->prefixes_.find (exact_search);
if (p != m_->prefixes_.end () && p->exact_) 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 ()) while (search_prefix.size ())
@ -397,9 +409,11 @@ auto AD1CCty::lookup (QString const& call) const -> Record
auto p = m_->prefixes_.find (search_prefix); auto p = m_->prefixes_.find (search_prefix);
if (p != m_->prefixes_.end ()) 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); search_prefix = search_prefix.left (search_prefix.size () - 1);

View File

@ -1,17 +1,19 @@
#ifndef AD1C_CTY_HPP_ #ifndef AD1C_CTY_HPP_
#define AD1C_CTY_HPP_ #define AD1C_CTY_HPP_
#include <boost/core/noncopyable.hpp>
#include <QObject> #include <QObject>
#include <QDebug>
#include "pimpl_h.hpp" #include "pimpl_h.hpp"
class QString;
class Configuration;
// //
// AD1CCty - Fast access database of Jim Reisert, AD1C's, cty.dat // AD1CCty - Fast access database of Jim Reisert, AD1C's, cty.dat
// entity and entity override information file. // entity and entity override information file.
// //
class AD1CCty final class AD1CCty final
: public QObject : public QObject
, private boost::noncopyable
{ {
Q_OBJECT Q_OBJECT
@ -39,7 +41,7 @@ public:
QString primary_prefix; QString primary_prefix;
}; };
explicit AD1CCty (); explicit AD1CCty (Configuration const *);
~AD1CCty (); ~AD1CCty ();
Record lookup (QString const& call) const; 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 <QFileInfo>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include "Configuration.hpp"
#include "qt_helpers.hpp" #include "qt_helpers.hpp"
#include "pimpl_impl.hpp" #include "pimpl_impl.hpp"
@ -361,8 +361,9 @@ namespace
class WorkedBefore::impl final class WorkedBefore::impl final
{ {
public: public:
impl () impl (Configuration const * configuration)
: path_ {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (logFileName)} : path_ {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (logFileName)}
, prefixes_ {configuration}
{ {
} }
@ -379,8 +380,10 @@ public:
worked_before_database_type worked_; 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] () { connect (&m_->loader_watcher_, &QFutureWatcher<worked_before_database_type>::finished, [this] () {
QString error; QString error;
size_t n {0}; size_t n {0};
@ -412,9 +415,9 @@ QString const& WorkedBefore::path () const
return m_->path_; 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 bool WorkedBefore::add (QString const& call

View File

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

View File

@ -3,15 +3,25 @@
#include <QDateTime> #include <QDateTime>
#include "Configuration.hpp" #include "Configuration.hpp"
#include "AD1CCty.hpp" #include "AD1CCty.hpp"
#include "Multiplier.hpp"
#include "logbook/AD1CCty.hpp"
#include "models/CabrilloLog.hpp"
#include "models/FoxLog.hpp"
#include "moc_logbook.cpp" #include "moc_logbook.cpp"
LogBook::LogBook (Configuration const * configuration) LogBook::LogBook (Configuration const * configuration)
: config_ {configuration} : config_ {configuration}
, worked_before_ {configuration}
{ {
Q_ASSERT (configuration);
connect (&worked_before_, &WorkedBefore::finished_loading, this, &LogBook::finished_loading); connect (&worked_before_, &WorkedBefore::finished_loading, this, &LogBook::finished_loading);
} }
LogBook::~LogBook ()
{
}
void LogBook::match (QString const& call, QString const& mode, QString const& grid, void LogBook::match (QString const& call, QString const& mode, QString const& grid,
AD1CCty::Record const& looked_up, AD1CCty::Record const& looked_up,
bool& callB4, bool& callB4,
@ -136,3 +146,40 @@ QByteArray LogBook::QSOToADIF (QString const& hisCall, QString const& hisGrid, Q
} }
return t.toLatin1(); 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 <QObject>
#include <QString> #include <QString>
#include <QScopedPointer>
#include "WorkedBefore.hpp" #include "WorkedBefore.hpp"
class Configuration; class Configuration;
class QByteArray; class QByteArray;
class QDateTime; class QDateTime;
class CabrilloLog;
class Multiplier;
class FoxLog;
class LogBook final class LogBook final
: public QObject : public QObject
@ -22,13 +26,14 @@ class LogBook final
public: public:
LogBook (Configuration const *); LogBook (Configuration const *);
~LogBook ();
QString const& path () const {return worked_before_.path ();} QString const& path () const {return worked_before_.path ();}
bool add (QString const& call bool add (QString const& call
, QString const& grid , QString const& grid
, QString const& band , QString const& band
, QString const& mode , QString const& mode
, QByteArray const& ADIF_record); , QByteArray const& ADIF_record);
AD1CCty const& countries () const {return worked_before_.countries ();} AD1CCty const * countries () const {return worked_before_.countries ();}
void rescan (); void rescan ();
void match (QString const& call, QString const& mode, QString const& grid, void match (QString const& call, QString const& mode, QString const& grid,
AD1CCty::Record const&, bool& callB4, bool& countryB4, 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; 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: private:
Configuration const * config_; Configuration const * config_;
WorkedBefore worked_before_; WorkedBefore worked_before_;
QScopedPointer<CabrilloLog> contest_log_;
QScopedPointer<Multiplier> mutable multiplier_;
QScopedPointer<FoxLog> fox_log_;
}; };
#endif #endif

View File

@ -2,10 +2,12 @@ SOURCES += \
logbook/countriesworked.cpp \ logbook/countriesworked.cpp \
logbook/logbook.cpp \ logbook/logbook.cpp \
logbook/AD1CCty.cpp \ logbook/AD1CCty.cpp \
logbook/WorkedBefore.cpp logbook/WorkedBefore.cpp \
logbook/Multiplier.cpp
HEADERS += \ HEADERS += \
logbook/WorkedBefore.hpp \ logbook/WorkedBefore.hpp \
logbook/logbook.h \ logbook/logbook.h \
logbook/countriesworked.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) catch (std::exception const& e)
{ {
MessageBox::critical_message (nullptr, QApplication::translate ("main", "Fatal error"), e.what ());
std::cerr << "Error: " << e.what () << '\n'; std::cerr << "Error: " << e.what () << '\n';
} }
catch (...) catch (...)
{ {
MessageBox::critical_message (nullptr, QApplication::translate ("main", "Unexpected fatal error"));
std::cerr << "Unexpected fatal error\n"; std::cerr << "Unexpected fatal error\n";
throw; // hoping the runtime might tell us more about the exception throw; // hoping the runtime might tell us more about the exception
} }

View File

@ -12,6 +12,7 @@
#include <QDataStream> #include <QDataStream>
#include "Configuration.hpp" #include "Configuration.hpp"
#include "Bands.hpp" #include "Bands.hpp"
#include "logbook/AD1CCty.hpp"
#include "qt_db_helpers.hpp" #include "qt_db_helpers.hpp"
#include "pimpl_impl.hpp" #include "pimpl_impl.hpp"
@ -19,14 +20,43 @@ class CabrilloLog::impl final
: public QSqlTableModel : public QSqlTableModel
{ {
public: 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); return QSqlTableModel::columnCount () + 1;
if (index.column () == fieldIndex ("when") }
Qt::ItemFlags flags (QModelIndex const& index) const override
{
auto flags = QSqlTableModel::flags (index);
if (index.isValid () && index.column () == columnCount (index) - 1)
{
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)
{
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)) && (Qt::DisplayRole == role || Qt::EditRole == role))
{ { // adjust date/time to Qt format
auto t = QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC); auto t = QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC);
if (Qt::DisplayRole == role) if (Qt::DisplayRole == role)
{ {
@ -35,43 +65,64 @@ public:
} }
value = t; value = t;
} }
}
return value; return value;
} }
QString cabrillo_frequency_string (Radio::Frequency frequency) const; QString cabrillo_frequency_string (Radio::Frequency frequency) const;
void create_table ();
CabrilloLog * self_;
Configuration const * configuration_; Configuration const * configuration_;
QSqlQuery mutable dupe_query_; QSqlQuery mutable dupe_query_;
QSqlQuery mutable export_query_; QSqlQuery mutable export_query_;
bool adding_row_;
}; };
CabrilloLog::impl::impl (Configuration const * configuration) CabrilloLog::impl::impl (CabrilloLog * self, Configuration const * configuration)
: QSqlTableModel {} : self_ {self}
, configuration_ {configuration} , configuration_ {configuration}
, adding_row_ {false}
{ {
if (!database ().tables ().contains ("cabrillo_log")) if (!database ().tables ().contains ("cabrillo_log_v2"))
{ {
QSqlQuery query; create_table ();
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"
")");
} }
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, SQL_error_check (dupe_query_, &QSqlQuery::prepare,
"SELECT " "SELECT "
" COUNT(*) " " frequency "
" FROM " " FROM "
" cabrillo_log " " cabrillo_log_v2 "
" WHERE " " WHERE "
" call = :call " " call = :call ");
" AND band = :band");
SQL_error_check (export_query_, &QSqlQuery::prepare, SQL_error_check (export_query_, &QSqlQuery::prepare,
"SELECT " "SELECT "
@ -81,32 +132,31 @@ CabrilloLog::impl::impl (Configuration const * configuration)
" , call" " , call"
" , exchange_rcvd" " , exchange_rcvd"
" FROM " " FROM "
" cabrillo_log " " cabrillo_log_v2 "
" ORDER BY " " ORDER BY "
" \"when\""); " \"when\"");
}
setEditStrategy (QSqlTableModel::OnFieldChange); void CabrilloLog::impl::create_table ()
setTable ("cabrillo_log"); {
setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(kHz)")); QSqlQuery query;
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); SQL_error_check (query, static_cast<bool (QSqlQuery::*) (QString const&)> (&QSqlQuery::exec),
setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call")); "CREATE TABLE cabrillo_log_v2 ("
setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent")); " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd")); " frequency INTEGER NOT NULL,"
setHeaderData (fieldIndex ("band"), Qt::Horizontal, tr ("Band")); " mode VARCHAR(6) NOT NULL,"
" \"when\" DATETIME NOT NULL,"
// This descending order by time is important, it makes the view " call VARCHAR(20) NOT NULL,"
// place the latest row at the top, without this the model/view " exchange_sent VARCHAR(32) NOT NULL,"
// interactions are both sluggish and unhelpful. " exchange_rcvd VARCHAR(32) NOT NULL"
setSort (fieldIndex ("when"), Qt::DescendingOrder); ")");
SQL_error_check (*this, &QSqlTableModel::select);
} }
// frequency here is in kHz // frequency here is in kHz
QString CabrilloLog::impl::cabrillo_frequency_string (Radio::Frequency frequency) const QString CabrilloLog::impl::cabrillo_frequency_string (Radio::Frequency frequency) const
{ {
QString result; QString result;
auto band = configuration_->bands ()->find (frequency * 1000ull); auto band = configuration_->bands ()->find (frequency);
if ("1mm" == band) result = "LIGHT"; if ("1mm" == band) result = "LIGHT";
else if ("2mm" == band) result = "241G"; else if ("2mm" == band) result = "241G";
else if ("2.5mm" == band) result = "134G"; 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 ("2m" == band) result = "144";
else if ("4m" == band) result = "70"; else if ("4m" == band) result = "70";
else if ("6m" == band) result = "50"; else if ("6m" == band) result = "50";
else result = QString::number (frequency); else result = QString::number (frequency / 1000ull);
return result; return result;
} }
CabrilloLog::CabrilloLog (Configuration const * configuration) #include "moc_CabrilloLog.cpp"
: m_ {configuration}
CabrilloLog::CabrilloLog (Configuration const * configuration, QObject * parent)
: QObject {parent}
, m_ {this, configuration}
{ {
Q_ASSERT (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) , QString const& exchange_sent, QString const& exchange_received)
{ {
auto record = m_->record (); auto record = m_->record ();
record.setValue ("frequency", frequency / 1000ull); // kHz record.setValue ("frequency", frequency);
record.setValue ("mode", mode);
if (!when.isNull ()) if (!when.isNull ())
{ {
record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); 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, "call", call);
set_value_maybe_null (record, "exchange_sent", exchange_sent); set_value_maybe_null (record, "exchange_sent", exchange_sent);
set_value_maybe_null (record, "exchange_rcvd", exchange_received); set_value_maybe_null (record, "exchange_rcvd", exchange_received);
set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency));
if (m_->isDirty ()) if (m_->isDirty ())
{ {
m_->revert (); // discard any uncommitted changes m_->revert (); // discard any uncommitted changes
} }
m_->setEditStrategy (QSqlTableModel::OnManualSubmit); m_->setEditStrategy (QSqlTableModel::OnManualSubmit);
ConditionalTransaction transaction {*m_}; ConditionalTransaction transaction {*m_};
m_->adding_row_ = true;
auto ok = m_->insertRecord (-1, record); auto ok = m_->insertRecord (-1, record);
transaction.submit (); transaction.submit ();
m_->adding_row_ = false;
m_->setEditStrategy (QSqlTableModel::OnFieldChange); m_->setEditStrategy (QSqlTableModel::OnFieldChange);
return ok; 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 bool CabrilloLog::dupe (Frequency frequency, QString const& call) const
{ {
m_->dupe_query_.bindValue (":call", call); 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)); SQL_error_check (m_->dupe_query_, static_cast<bool (QSqlQuery::*) ()> (&QSqlQuery::exec));
m_->dupe_query_.next (); auto record = m_->dupe_query_.record ();
return m_->dupe_query_.value (0).toInt (); 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 () void CabrilloLog::reset ()
@ -208,6 +271,7 @@ void CabrilloLog::reset ()
transaction.submit (); transaction.submit ();
m_->select (); // to refresh views m_->select (); // to refresh views
m_->setEditStrategy (QSqlTableModel::OnFieldChange); 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)); SQL_error_check (m_->export_query_, static_cast<bool (QSqlQuery::*) ()> (&QSqlQuery::exec));
auto record = m_->export_query_.record (); auto record = m_->export_query_.record ();
auto frequency_index = record.indexOf ("frequency"); auto frequency_index = record.indexOf ("frequency");
// auto mode_index = record.indexOf ("mode");
auto when_index = record.indexOf ("when"); auto when_index = record.indexOf ("when");
auto call_index = record.indexOf ("call"); auto call_index = record.indexOf ("call");
auto sent_index = record.indexOf ("exchange_sent"); 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); .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_ #ifndef CABRILLO_LOG_HPP_
#define CABRILLO_LOG_HPP_ #define CABRILLO_LOG_HPP_
#include <boost/core/noncopyable.hpp> #include <QObject>
#include <QSet>
#include <QPair>
#include <QString>
#include "Radio.hpp" #include "Radio.hpp"
#include "pimpl_h.hpp" #include "pimpl_h.hpp"
class Configuration; class Configuration;
class QDateTime; class QDateTime;
class QString;
class QSqlTableModel; class QSqlTableModel;
class QTextStream; class QTextStream;
class AD1CCty;
class CabrilloLog final class CabrilloLog final
: private boost::noncopyable : public QObject
{ {
Q_OBJECT
public: public:
using Frequency = Radio::Frequency; 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 (); ~CabrilloLog ();
// returns false if insert fails // 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); , QString const& report_sent, QString const& report_received);
bool dupe (Frequency, QString const& call) const; bool dupe (Frequency, QString const& call) const;
QSqlTableModel * model (); QSqlTableModel * model ();
void reset (); void reset ();
void export_qsos (QTextStream&) const; void export_qsos (QTextStream&) const;
worked_set unique_DXCC_entities (AD1CCty const *) const;
Q_SIGNAL void data_changed () const;
private: private:
class impl; class impl;

View File

@ -127,7 +127,9 @@ namespace
{7074000, Modes::FT8, IARURegions::ALL}, {7074000, Modes::FT8, IARURegions::ALL},
{7076000, Modes::JT65, IARURegions::ALL}, {7076000, Modes::JT65, IARURegions::ALL},
{7078000, Modes::JT9, 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) // Band plans (all USB dial unless stated otherwise)
// //

View File

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

View File

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

View File

@ -1,10 +1,12 @@
#include "CabrilloLogWindow.hpp" #include "CabrilloLogWindow.hpp"
#include <stdexcept>
#include <QApplication> #include <QApplication>
#include <QIdentityProxyModel> #include <QIdentityProxyModel>
#include <QSqlTableModel> #include <QSqlTableModel>
#include "Configuration.hpp" #include "Configuration.hpp"
#include "models/Bands.hpp" #include "models/Bands.hpp"
#include "item_delegates/FrequencyDelegate.hpp"
#include "item_delegates/ForeignKeyDelegate.hpp" #include "item_delegates/ForeignKeyDelegate.hpp"
#include "item_delegates/CallsignDelegate.hpp" #include "item_delegates/CallsignDelegate.hpp"
#include "pimpl_impl.hpp" #include "pimpl_impl.hpp"
@ -29,7 +31,7 @@ namespace
switch (index.column ()) switch (index.column ())
{ {
case 1: case 1:
case 6: case 7:
return Qt::AlignRight + Qt::AlignVCenter; return Qt::AlignRight + Qt::AlignVCenter;
default: default:
break; break;
@ -63,10 +65,10 @@ CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const
m_->format_model_.setSourceModel (m_->log_model_); m_->format_model_.setSourceModel (m_->log_model_);
m_->ui_.log_table_view->setModel (&m_->format_model_); m_->ui_.log_table_view->setModel (&m_->format_model_);
set_log_view (m_->ui_.log_table_view); set_log_view (m_->ui_.log_table_view);
m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (1, new FrequencyDelegate {this});
m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), 0, this}); m_->ui_.log_table_view->setItemDelegateForColumn (4, new CallsignDelegate {this});
auto h_header = m_->ui_.log_table_view->horizontalHeader (); 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 () 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)); 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; class QWidget;
// //
// MHz frequency line edits with validation // MHz frequency line edit with validation
// //
class FrequencyLineEdit final class FrequencyLineEdit final
: public QLineEdit : public QLineEdit
@ -26,20 +26,4 @@ public:
void frequency (Frequency); 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 #endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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