Add mode dependent working frequencies

Working frequencies are mode dependent  and a reset to defaults button
has been added.

Also re-factored much of the model  and item delegate code to simplify
several  of the  model  implementations. Introduced  a single  routine
called from main to register the custom types with Qt.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5453 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2015-05-28 23:22:17 +00:00
parent e674ac4cb0
commit f200506571
30 changed files with 1319 additions and 940 deletions

View File

@ -1,18 +1,5 @@
#include "AudioDevice.hpp" #include "AudioDevice.hpp"
#include <QMetaType>
namespace
{
struct init
{
init ()
{
qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel");
}
} static_initializer;
}
bool AudioDevice::initialize (OpenMode mode, Channel channel) bool AudioDevice::initialize (OpenMode mode, Channel channel)
{ {
m_channel = channel; m_channel = channel;

389
Bands.cpp
View File

@ -1,196 +1,193 @@
#include "Bands.hpp" #include "Bands.hpp"
#include <algorithm> #include <algorithm>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
namespace namespace
{ {
// Local structure to hold a single ADIF band definition. // Local structure to hold a single ADIF band definition.
struct ADIF_band
{ // Table of ADIF band definitions as defined in the ADIF
char const * const name_; // specification.
Radio::Frequency lower_bound_; Bands::ADIFBand constexpr ADIF_bands[] = {
Radio::Frequency upper_bound_; {"2190m", 136000u, 137000u},
}; {"630m", 472000u, 479000u},
{"560m", 501000u, 504000u},
// Table of ADIF band definitions as defined in the ADIF {"160m", 1800000u, 2000000u},
// specification. {"80m", 3500000u, 4000000u},
ADIF_band constexpr ADIF_bands[] = { {"60m", 5102000u, 5406500u},
{"2190m", 136000u, 137000u}, {"40m", 7000000u, 7300000u},
{"630m", 472000u, 479000u}, {"30m", 10000000u, 10150000u},
{"560m", 501000u, 504000u}, {"20m", 14000000u, 14350000u},
{"160m", 1800000u, 2000000u}, {"17m", 18068000u, 18168000u},
{"80m", 3500000u, 4000000u}, {"15m", 21000000u, 21450000u},
{"60m", 5102000u, 5406500u}, {"12m", 24890000u, 24990000u},
{"40m", 7000000u, 7300000u}, {"10m", 28000000u, 29700000u},
{"30m", 10000000u, 10150000u}, {"6m", 50000000u, 54000000u},
{"20m", 14000000u, 14350000u}, {"4m", 70000000u, 71000000u},
{"17m", 18068000u, 18168000u}, {"2m", 144000000u, 148000000u},
{"15m", 21000000u, 21450000u}, {"1.25m", 222000000u, 225000000u},
{"12m", 24890000u, 24990000u}, {"70cm", 420000000u, 450000000u},
{"10m", 28000000u, 29700000u}, {"33cm", 902000000u, 928000000u},
{"6m", 50000000u, 54000000u}, {"23cm", 1240000000u, 1300000000u},
{"4m", 70000000u, 71000000u}, {"13cm", 2300000000u, 2450000000u},
{"2m", 144000000u, 148000000u}, {"9cm", 3300000000u, 3500000000u},
{"1.25m", 222000000u, 225000000u}, {"6cm", 5650000000u, 5925000000u},
{"70cm", 420000000u, 450000000u}, {"3cm", 10000000000u, 10500000000u},
{"33cm", 902000000u, 928000000u}, {"1.25cm",24000000000u, 24250000000u},
{"23cm", 1240000000u, 1300000000u}, {"6mm", 47000000000u, 47200000000u},
{"13cm", 2300000000u, 2450000000u}, {"4mm", 75500000000u, 81000000000u},
{"9cm", 3300000000u, 3500000000u}, {"2.5mm", 119980000000u,120020000000u},
{"6cm", 5650000000u, 5925000000u}, {"2mm", 142000000000u,149000000000u},
{"3cm", 10000000000u, 10500000000u}, {"1mm", 241000000000u,250000000000u},
{"1.25cm", 24000000000u, 24250000000u}, };
{"6mm", 47000000000u, 47200000000u},
{"4mm", 75500000000u, 81000000000u}, Bands::ADIFBand constexpr oob = {"OOB", 0, std::numeric_limits<Bands::Frequency>::max ()};
{"2.5mm", 119980000000u, 120020000000u},
{"2mm", 142000000000u, 149000000000u}, int constexpr table_rows ()
{"1mm", 241000000000u, 250000000000u}, {
}; return sizeof (ADIF_bands) / sizeof (ADIF_bands[0]);
}
auto constexpr out_of_band = "OOB"; }
int constexpr table_rows () Bands::Bands (QObject * parent)
{ : QAbstractTableModel {parent}
return sizeof (ADIF_bands) / sizeof (ADIF_bands[0]); {
} }
}
auto Bands::find (Frequency f) const -> ADIFBand const *
Bands::Bands (QObject * parent) {
: QAbstractTableModel {parent} auto const& end_iter = ADIF_bands + table_rows ();
{ auto const& row_iter = std::find_if (ADIF_bands, end_iter, [f] (ADIFBand const& band) {
} return band.lower_bound_ <= f && f <= band.upper_bound_;
});
QModelIndex Bands::find (QVariant const& v) const if (row_iter != end_iter)
{ {
auto f = v.value<Radio::Frequency> (); return row_iter;
auto end_iter = ADIF_bands + table_rows (); }
auto row_iter = std::find_if (ADIF_bands, end_iter, [f] (ADIF_band const& band) { return &oob;
return band.lower_bound_ <= f && f <= band.upper_bound_; }
});
if (row_iter != end_iter) auto Bands::out_of_band () const -> ADIFBand const *
{ {
return index (row_iter - ADIF_bands, 0); // return the band row index return &oob;
} }
return QModelIndex {}; int Bands::rowCount (QModelIndex const& parent) const
} {
return parent.isValid () ? 0 : table_rows ();
int Bands::rowCount (QModelIndex const& parent) const }
{
return parent.isValid () ? 0 : table_rows (); int Bands::columnCount (QModelIndex const& parent) const
} {
return parent.isValid () ? 0 : 3;
int Bands::columnCount (QModelIndex const& parent) const }
{
return parent.isValid () ? 0 : 3; Qt::ItemFlags Bands::flags (QModelIndex const& index) const
} {
return QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled;
Qt::ItemFlags Bands::flags (QModelIndex const& index) const }
{
return QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; QVariant Bands::data (QModelIndex const& index, int role) const
} {
QVariant item;
QVariant Bands::data (QModelIndex const& index, int role) const
{ if (!index.isValid ())
QVariant item; {
// Hijack root for OOB string.
if (!index.isValid ()) if (Qt::DisplayRole == role)
{ {
// Hijack root for OOB string. item = oob.name_;
if (Qt::DisplayRole == role) }
{ }
item = out_of_band; else
} {
} auto row = index.row ();
else auto column = index.column ();
{
auto row = index.row (); if (row < table_rows ())
auto column = index.column (); {
switch (role)
if (row < table_rows ()) {
{ case Qt::ToolTipRole:
switch (role) case Qt::AccessibleDescriptionRole:
{ switch (column)
case Qt::ToolTipRole: {
case Qt::AccessibleDescriptionRole: case 0: item = tr ("Band name"); break;
switch (column) case 1: item = tr ("Lower frequency limit"); break;
{ case 2: item = tr ("Upper frequency limit"); break;
case 0: item = tr ("Band name"); break; }
case 1: item = tr ("Lower frequency limit"); break; break;
case 2: item = tr ("Upper frequency limit"); break;
} case SortRole:
break; case Qt::DisplayRole:
case Qt::EditRole:
case SortRole: switch (column)
case Qt::DisplayRole: {
case Qt::EditRole: case 0:
switch (column) if (SortRole == role)
{ {
case 0: // band name sorts by lower bound
if (SortRole == role) item = ADIF_bands[row].lower_bound_;
{ }
// band name sorts by lower bound else
item = ADIF_bands[row].lower_bound_; {
} item = ADIF_bands[row].name_;
else }
{ break;
item = ADIF_bands[row].name_;
} case 1: item = ADIF_bands[row].lower_bound_; break;
break; case 2: item = ADIF_bands[row].upper_bound_; break;
}
case 1: item = ADIF_bands[row].lower_bound_; break; break;
case 2: item = ADIF_bands[row].upper_bound_; break;
} case Qt::AccessibleTextRole:
break; switch (column)
{
case Qt::AccessibleTextRole: case 0: item = ADIF_bands[row].name_; break;
switch (column) case 1: item = ADIF_bands[row].lower_bound_; break;
{ case 2: item = ADIF_bands[row].upper_bound_; break;
case 0: item = ADIF_bands[row].name_; break; }
case 1: item = ADIF_bands[row].lower_bound_; break; break;
case 2: item = ADIF_bands[row].upper_bound_; break;
} case Qt::TextAlignmentRole:
break; switch (column)
{
case Qt::TextAlignmentRole: case 0:
switch (column) item = Qt::AlignHCenter + Qt::AlignVCenter;
{ break;
case 0:
item = Qt::AlignHCenter + Qt::AlignVCenter; case 1:
break; case 2:
item = Qt::AlignRight + Qt::AlignVCenter;
case 1: break;
case 2: }
item = Qt::AlignRight + Qt::AlignVCenter; break;
break; }
} }
break; }
} return item;
} }
}
return item; QVariant Bands::headerData (int section, Qt::Orientation orientation, int role) const
} {
QVariant result;
QVariant Bands::headerData (int section, Qt::Orientation orientation, int role) const
{ if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
QVariant result; {
switch (section)
if (Qt::DisplayRole == role && Qt::Horizontal == orientation) {
{ case 0: result = tr ("Band"); break;
switch (section) case 1: result = tr ("Lower Limit"); break;
{ case 2: result = tr ("Upper Limit"); break;
case 0: result = tr ("Band"); break; }
case 1: result = tr ("Lower Limit"); break; }
case 2: result = tr ("Upper Limit"); break; else
} {
} result = QAbstractTableModel::headerData (section, orientation, role);
else }
{
result = QAbstractTableModel::headerData (section, orientation, role); return result;
} }
return result;
}

126
Bands.hpp
View File

@ -1,58 +1,68 @@
#ifndef BANDS_HPP__ #ifndef BANDS_HPP__
#define BANDS_HPP__ #define BANDS_HPP__
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include "Radio.hpp" #include "Radio.hpp"
// //
// Class Bands // Class Bands
// //
// Encapsulates information about amateur radio bands as defined by // Encapsulates information about amateur radio bands as defined by
// the ADIF specification. The model is immutable. The rows are // the ADIF specification. The model is immutable. The rows are
// stored in asscending order of frequency. // stored in asscending order of frequency.
// //
// Responsibilities // Responsibilities
// //
// Provides a well known band name mapped to lower and upper // Provides a well known band name mapped to lower and upper
// frequency limits. Also provides a convenience operation to // frequency limits. Also provides a convenience operation to
// determine the band details for any given frequency, the result of // determine the band details for any given frequency, the result of
// which may be invalid if the given frequency doesn't lie within a // which may be invalid if the given frequency doesn't lie within a
// recognised band. // recognised band.
// //
// Collaborations // Collaborations
// //
// Implements the QAbstractTableModel interface as an immutable table // Implements the QAbstractTableModel interface as an immutable table
// where rows are bands and columns are band name, lower frequency // where rows are bands and columns are band name, lower frequency
// limit and, upper ferquency limit respectively. // limit and, upper ferquency limit respectively.
// //
class Bands final class Bands final
: public QAbstractTableModel : public QAbstractTableModel
{ {
public: public:
explicit Bands (QObject * parent = nullptr); using Frequency = Radio::Frequency;
// struct ADIFBand
// Model API {
// char const * const name_;
QModelIndex find (QVariant const&) const; // find band Frequency is in Radio::Frequency lower_bound_;
Radio::Frequency upper_bound_;
// Custom role for sorting. };
static int constexpr SortRole = Qt::UserRole;
explicit Bands (QObject * parent = nullptr);
// Implement the QAbstractTableModel interface
int rowCount (QModelIndex const& parent = QModelIndex {}) const override; //
int columnCount (QModelIndex const& parent = QModelIndex {}) const override; // Model API
Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; //
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; ADIFBand const * find (Frequency) const; // find band Frequency is in
ADIFBand const * out_of_band () const;
// The value return for the Qt::DisplayRole role for the root of the
// model (invalid index) is a special string representing out of // Custom role for sorting.
// band. static int constexpr SortRole = Qt::UserRole;
//
// All columns return a number for the custom role SortRole, this // Implement the QAbstractTableModel interface
// number defines a strict frequency order for the rows. int rowCount (QModelIndex const& parent = QModelIndex {}) const override;
QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; int columnCount (QModelIndex const& parent = QModelIndex {}) const override;
}; Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override;
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
#endif
// The value return for the Qt::DisplayRole role for the root of the
// model (invalid index) is a special string representing out of
// band.
//
// All columns return a number for the custom role SortRole, this
// number defines a strict frequency order for the rows.
QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override;
};
#endif

View File

@ -177,11 +177,13 @@ endif (APPLE)
# #
set (wsjt_qt_CXXSRCS set (wsjt_qt_CXXSRCS
qt_helpers.cpp qt_helpers.cpp
MetaDataRegistry.cpp
NetworkServerLookup.cpp NetworkServerLookup.cpp
revision_utils.cpp revision_utils.cpp
WFPalette.cpp WFPalette.cpp
Radio.cpp Radio.cpp
Bands.cpp Bands.cpp
Modes.cpp
FrequencyList.cpp FrequencyList.cpp
StationList.cpp StationList.cpp
FrequencyLineEdit.cpp FrequencyLineEdit.cpp

View File

@ -8,11 +8,11 @@
class CandidateKeyFilter::impl final class CandidateKeyFilter::impl final
{ {
public: public:
explicit impl (QAbstractItemModel const * referencing_model explicit impl (int referenced_key_column
, int referenced_key_role
, QAbstractItemModel const * referencing_model
, int referencing_key_column , int referencing_key_column
, int referenced_key_column , int referencing_key_role)
, int referencing_key_role
, int referenced_key_role)
: referencing_ {referencing_model} : referencing_ {referencing_model}
, referencing_key_column_ {referencing_key_column} , referencing_key_column_ {referencing_key_column}
, referencing_key_role_ {referencing_key_role} , referencing_key_role_ {referencing_key_role}
@ -29,14 +29,25 @@ public:
QModelIndex active_key_; QModelIndex active_key_;
}; };
CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel const * referencing_model CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel * referenced_model
, QAbstractItemModel * referenced_model
, int referencing_key_column
, int referenced_key_column , int referenced_key_column
, int referencing_key_role , QObject * parent
, int referenced_key_role) , int referenced_key_role)
: QSortFilterProxyModel {nullptr} // ForeignKeyDelegate owns us : QSortFilterProxyModel {parent}
, m_ {referencing_model, referencing_key_column, referenced_key_column, referencing_key_role, referenced_key_role} , m_ {referenced_key_column, referenced_key_role, nullptr, 0, Qt::EditRole}
{
setSourceModel (referenced_model);
}
CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent
, int referenced_key_role
, int referencing_key_role)
: QSortFilterProxyModel {parent}
, m_ {referenced_key_column, referenced_key_role, referencing_model, referencing_key_column, referencing_key_role}
{ {
setSourceModel (referenced_model); setSourceModel (referenced_model);
} }
@ -47,16 +58,24 @@ CandidateKeyFilter::~CandidateKeyFilter ()
void CandidateKeyFilter::set_active_key (QModelIndex const& index) void CandidateKeyFilter::set_active_key (QModelIndex const& index)
{ {
if (index.isValid () ) if (m_->referencing_)
{ {
Q_ASSERT (index.column () == m_->referencing_key_column_); if (index.isValid () )
m_->active_key_ = index; {
Q_ASSERT (index.column () == m_->referencing_key_column_);
m_->active_key_ = index;
}
invalidateFilter ();
} }
invalidateFilter ();
} }
bool CandidateKeyFilter::filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const bool CandidateKeyFilter::filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const
{ {
if (!m_->referencing_) // many to many passes all
{
return true;
}
auto candidate_key = sourceModel ()->index (candidate_row, m_->referenced_key_column_, candidate_parent).data (m_->referenced_key_role_); auto candidate_key = sourceModel ()->index (candidate_row, m_->referenced_key_column_, candidate_parent).data (m_->referenced_key_role_);
// Include the current key. // Include the current key.

View File

@ -12,12 +12,17 @@ class CandidateKeyFilter final
: public QSortFilterProxyModel : public QSortFilterProxyModel
{ {
public: public:
explicit CandidateKeyFilter (QAbstractItemModel const * referencing_model explicit CandidateKeyFilter (QAbstractItemModel * referenced_model
, QAbstractItemModel * referenced_model , int referenced_key_column
, int referencing_key_column = 0 , QObject * parent = nullptr
, int referenced_key_column = 0
, int referencing_key_role = Qt::EditRole
, int referenced_key_role = Qt::EditRole); , int referenced_key_role = Qt::EditRole);
explicit CandidateKeyFilter (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent = nullptr
, int referenced_key_role = Qt::EditRole
, int referencing_key_role = Qt::EditRole);
~CandidateKeyFilter (); ~CandidateKeyFilter ();
// this key is not to be filtered, usually because we want to allow // this key is not to be filtered, usually because we want to allow

View File

@ -171,6 +171,7 @@
#include "TransceiverFactory.hpp" #include "TransceiverFactory.hpp"
#include "Transceiver.hpp" #include "Transceiver.hpp"
#include "Bands.hpp" #include "Bands.hpp"
#include "Modes.hpp"
#include "FrequencyList.hpp" #include "FrequencyList.hpp"
#include "StationList.hpp" #include "StationList.hpp"
#include "NetworkServerLookup.hpp" #include "NetworkServerLookup.hpp"
@ -182,17 +183,6 @@
namespace namespace
{ {
struct init
{
init ()
{
qRegisterMetaType<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaType<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
}
} static_initializer;
// these undocumented flag values when stored in (Qt::UserRole - 1) // these undocumented flag values when stored in (Qt::UserRole - 1)
// of a ComboBox item model index allow the item to be enabled or // of a ComboBox item model index allow the item to be enabled or
// disabled // disabled
@ -210,14 +200,17 @@ class FrequencyDialog final
: public QDialog : public QDialog
{ {
public: public:
using Frequency = Radio::Frequency; using Item = FrequencyList::Item;
explicit FrequencyDialog (QWidget * parent = nullptr) explicit FrequencyDialog (Modes * modes_model, QWidget * parent = nullptr)
: QDialog {parent} : QDialog {parent}
{ {
setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Frequency")); setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Frequency"));
mode_combo_box_.setModel (modes_model);
auto form_layout = new QFormLayout (); auto form_layout = new QFormLayout ();
form_layout->addRow (tr ("&Mode:"), &mode_combo_box_);
form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_); form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_);
auto main_layout = new QVBoxLayout (this); auto main_layout = new QVBoxLayout (this);
@ -230,12 +223,13 @@ public:
connect (button_box, &QDialogButtonBox::rejected, this, &FrequencyDialog::reject); connect (button_box, &QDialogButtonBox::rejected, this, &FrequencyDialog::reject);
} }
Frequency frequency () const Item item () const
{ {
return frequency_line_edit_.frequency (); return {frequency_line_edit_.frequency (), Modes::value (mode_combo_box_.currentText ())};
} }
private: private:
QComboBox mode_combo_box_;
FrequencyLineEdit frequency_line_edit_; FrequencyLineEdit frequency_line_edit_;
}; };
@ -249,7 +243,7 @@ class StationDialog final
public: public:
explicit StationDialog (StationList const * stations, Bands * bands, QWidget * parent = nullptr) explicit StationDialog (StationList const * stations, Bands * bands, QWidget * parent = nullptr)
: QDialog {parent} : QDialog {parent}
, filtered_bands_ {new CandidateKeyFilter {stations, bands}} , filtered_bands_ {new CandidateKeyFilter {bands, stations, 0, 0}}
{ {
setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Station")); setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Station"));
@ -311,6 +305,7 @@ public:
}; };
//
// Class MessageItemDelegate // Class MessageItemDelegate
// //
// Item delegate for message entry such as free text message macros. // Item delegate for message entry such as free text message macros.
@ -336,7 +331,6 @@ public:
} }
}; };
// Internal implementation of the Configuration class. // Internal implementation of the Configuration class.
class Configuration::impl final class Configuration::impl final
: public QDialog : public QDialog
@ -416,6 +410,7 @@ private:
void delete_selected_macros (QModelIndexList); void delete_selected_macros (QModelIndexList);
Q_SLOT void on_save_path_select_push_button_clicked (bool); Q_SLOT void on_save_path_select_push_button_clicked (bool);
Q_SLOT void delete_frequencies (); Q_SLOT void delete_frequencies ();
Q_SLOT void on_reset_frequencies_push_button_clicked (bool);
Q_SLOT void insert_frequency (); Q_SLOT void insert_frequency ();
Q_SLOT void delete_stations (); Q_SLOT void delete_stations ();
Q_SLOT void insert_station (); Q_SLOT void insert_station ();
@ -469,8 +464,9 @@ private:
QStringListModel macros_; QStringListModel macros_;
RearrangableMacrosModel next_macros_; RearrangableMacrosModel next_macros_;
QAction * macro_delete_action_; QAction * macro_delete_action_;
Bands bands_; Bands bands_;
Modes modes_;
FrequencyList frequencies_; FrequencyList frequencies_;
FrequencyList next_frequencies_; FrequencyList next_frequencies_;
StationList stations_; StationList stations_;
@ -697,24 +693,17 @@ void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_s
m_->sync_transceiver (force_signal); m_->sync_transceiver (force_signal);
} }
Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * parent) Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * parent)
: QDialog {parent} : QDialog {parent}
, self_ {self} , self_ {self}
, ui_ {new Ui::configuration_dialog} , ui_ {new Ui::configuration_dialog}
, settings_ {settings} , settings_ {settings}
, doc_dir_ {QApplication::applicationDirPath ()} , doc_dir_ {QApplication::applicationDirPath ()}
, frequencies_ { , frequencies_ {&bands_}
{ 136000, 136130, 474200, 1836600, 1838000, 3576000, 3592600, 5287200, 5357000, , next_frequencies_ {&bands_}
7038600, 7076000, 10138000, 10138700, 14076000, 14095600, 18102000, 18104600,
21076000, 21094600, 24917000, 24924600, 28076000, 28124600, 50276000, 50293000,
70091000, 144000000, 144489000, 222000000, 432000000, 432300000,
902000000, 1296000000, 1296500000, 2301000000, 2304000000, 2320000000, 3400000000,
3456000000, 5760000000,10368000000, 24048000000 }
}
, stations_ {&bands_} , stations_ {&bands_}
, next_stations_ {&bands_} , next_stations_ {&bands_}
, frequency_dialog_ {new FrequencyDialog {this}} , frequency_dialog_ {new FrequencyDialog {&modes_, this}}
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}} , station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
, rig_active_ {false} , rig_active_ {false}
, have_rig_ {false} , have_rig_ {false}
@ -891,12 +880,12 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
// //
// setup working frequencies table model & view // setup working frequencies table model & view
// //
frequencies_.sort (0); frequencies_.sort (FrequencyList::frequency_column);
ui_->frequencies_table_view->setModel (&next_frequencies_); ui_->frequencies_table_view->setModel (&next_frequencies_);
ui_->frequencies_table_view->sortByColumn (0, Qt::AscendingOrder); ui_->frequencies_table_view->sortByColumn (FrequencyList::frequency_column, Qt::AscendingOrder);
ui_->frequencies_table_view->setItemDelegateForColumn (0, new FrequencyItemDelegate {&bands_, this}); ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList::mode_column, new ForeignKeyDelegate {&modes_, 0, this});
ui_->frequencies_table_view->setColumnHidden (1, true); ui_->frequencies_table_view->setColumnHidden (FrequencyList::frequency_mhz_column, true);
frequency_delete_action_ = new QAction {tr ("&Delete"), ui_->frequencies_table_view}; frequency_delete_action_ = new QAction {tr ("&Delete"), ui_->frequencies_table_view};
ui_->frequencies_table_view->insertAction (nullptr, frequency_delete_action_); ui_->frequencies_table_view->insertAction (nullptr, frequency_delete_action_);
@ -910,13 +899,11 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
// //
// setup stations table model & view // setup stations table model & view
// //
stations_.sort (0); stations_.sort (StationList::band_column);
ui_->stations_table_view->setModel (&next_stations_); ui_->stations_table_view->setModel (&next_stations_);
ui_->stations_table_view->sortByColumn (0, Qt::AscendingOrder); ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder);
ui_->stations_table_view->setColumnWidth (1, 150); ui_->stations_table_view->setItemDelegateForColumn (StationList::band_column, new ForeignKeyDelegate {&bands_, &next_stations_, 0, StationList::band_column, this});
ui_->stations_table_view->setItemDelegateForColumn (0, new ForeignKeyDelegate {&next_stations_, &bands_, 0, 0, this});
ui_->stations_table_view->setItemDelegateForColumn (1, new FrequencyDeltaItemDelegate {this});
station_delete_action_ = new QAction {tr ("&Delete"), ui_->stations_table_view}; station_delete_action_ = new QAction {tr ("&Delete"), ui_->stations_table_view};
ui_->stations_table_view->insertAction (nullptr, station_delete_action_); ui_->stations_table_view->insertAction (nullptr, station_delete_action_);
@ -1041,8 +1028,8 @@ void Configuration::impl::initialize_models ()
} }
next_macros_.setStringList (macros_.stringList ()); next_macros_.setStringList (macros_.stringList ());
next_frequencies_ = frequencies_.frequencies (); next_frequencies_.frequency_list (frequencies_.frequency_list ());
next_stations_ = stations_.stations (); next_stations_.station_list (stations_.station_list ());
set_rig_invariants (); set_rig_invariants ();
} }
@ -1170,10 +1157,10 @@ void Configuration::impl::read_settings ()
if (settings_->contains ("frequencies")) if (settings_->contains ("frequencies"))
{ {
frequencies_ = settings_->value ("frequencies").value<Radio::Frequencies> (); frequencies_.frequency_list (settings_->value ("frequencies").value<FrequencyList::FrequencyItems> ());
} }
stations_ = settings_->value ("stations").value<StationList::Stations> (); stations_.station_list (settings_->value ("stations").value<StationList::Stations> ());
log_as_RTTY_ = settings_->value ("toRTTY", false).toBool (); log_as_RTTY_ = settings_->value ("toRTTY", false).toBool ();
report_in_comments_ = settings_->value("dBtoComments", false).toBool (); report_in_comments_ = settings_->value("dBtoComments", false).toBool ();
@ -1262,8 +1249,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("After73", id_after_73_); settings_->setValue ("After73", id_after_73_);
settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_); settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_);
settings_->setValue ("Macros", macros_.stringList ()); settings_->setValue ("Macros", macros_.stringList ());
settings_->setValue ("frequencies", QVariant::fromValue (frequencies_.frequencies ())); settings_->setValue ("frequencies", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("stations", QVariant::fromValue (stations_.stations ())); settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
settings_->setValue ("toRTTY", log_as_RTTY_); settings_->setValue ("toRTTY", log_as_RTTY_);
settings_->setValue ("dBtoComments", report_in_comments_); settings_->setValue ("dBtoComments", report_in_comments_);
settings_->setValue ("Rig", rig_params_.rig_name); settings_->setValue ("Rig", rig_params_.rig_name);
@ -1674,16 +1661,16 @@ void Configuration::impl::accept ()
macros_.setStringList (next_macros_.stringList ()); macros_.setStringList (next_macros_.stringList ());
} }
if (frequencies_.frequencies () != next_frequencies_.frequencies ()) if (frequencies_.frequency_list () != next_frequencies_.frequency_list ())
{ {
frequencies_ = next_frequencies_.frequencies (); frequencies_.frequency_list (next_frequencies_.frequency_list ());
frequencies_.sort (0); frequencies_.sort (FrequencyList::frequency_column);
} }
if (stations_.stations () != next_stations_.stations ()) if (stations_.station_list () != next_stations_.station_list ())
{ {
stations_ = next_stations_.stations (); stations_.station_list(next_stations_.station_list ());
stations_.sort (0); stations_.sort (StationList::band_column);
} }
write_settings (); // make visible to all write_settings (); // make visible to all
@ -1975,13 +1962,26 @@ void Configuration::impl::delete_frequencies ()
auto selection_model = ui_->frequencies_table_view->selectionModel (); auto selection_model = ui_->frequencies_table_view->selectionModel ();
selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
next_frequencies_.removeDisjointRows (selection_model->selectedRows ()); next_frequencies_.removeDisjointRows (selection_model->selectedRows ());
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList::mode_column);
}
void Configuration::impl::on_reset_frequencies_push_button_clicked (bool /* checked */)
{
if (QMessageBox::Yes == QMessageBox::question (this, tr ("Reset Working Frequencies")
, tr ("Are you sure you want to discard your current "
"working frequencies and replace them with default "
"ones?")))
{
next_frequencies_.reset_to_defaults ();
}
} }
void Configuration::impl::insert_frequency () void Configuration::impl::insert_frequency ()
{ {
if (QDialog::Accepted == frequency_dialog_->exec ()) if (QDialog::Accepted == frequency_dialog_->exec ())
{ {
ui_->frequencies_table_view->setCurrentIndex (next_frequencies_.add (frequency_dialog_->frequency ())); ui_->frequencies_table_view->setCurrentIndex (next_frequencies_.add (frequency_dialog_->item ()));
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList::mode_column);
} }
} }
@ -1990,6 +1990,8 @@ void Configuration::impl::delete_stations ()
auto selection_model = ui_->stations_table_view->selectionModel (); auto selection_model = ui_->stations_table_view->selectionModel ();
selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
next_stations_.removeDisjointRows (selection_model->selectedRows ()); next_stations_.removeDisjointRows (selection_model->selectedRows ());
ui_->stations_table_view->resizeColumnToContents (StationList::band_column);
ui_->stations_table_view->resizeColumnToContents (StationList::offset_column);
} }
void Configuration::impl::insert_station () void Configuration::impl::insert_station ()
@ -1997,6 +1999,8 @@ void Configuration::impl::insert_station ()
if (QDialog::Accepted == station_dialog_->exec ()) if (QDialog::Accepted == station_dialog_->exec ())
{ {
ui_->stations_table_view->setCurrentIndex (next_stations_.add (station_dialog_->station ())); ui_->stations_table_view->setCurrentIndex (next_stations_.add (station_dialog_->station ()));
ui_->stations_table_view->resizeColumnToContents (StationList::band_column);
ui_->stations_table_view->resizeColumnToContents (StationList::offset_column);
} }
} }

View File

@ -1807,9 +1807,15 @@ for assessing propagation and system performance.</string>
<property name="title"> <property name="title">
<string>Working Frequencies</string> <string>Working Frequencies</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_15"> <layout class="QHBoxLayout" name="horizontalLayout">
<item row="0" column="0" rowspan="2"> <item>
<widget class="QTableView" name="frequencies_table_view"> <widget class="QTableView" name="frequencies_table_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum> <enum>Qt::ActionsContextMenu</enum>
</property> </property>
@ -1836,113 +1842,128 @@ for assessing propagation and system performance.</string>
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="0" column="2"> <item>
<widget class="QGroupBox" name="groupBox_3"> <layout class="QVBoxLayout" name="verticalLayout_7">
<property name="toolTip"> <item>
<string>See WSPR documentattion Appendix C for details of how to determine these factors for your radio.</string> <layout class="QHBoxLayout" name="horizontalLayout_6">
</property> <item>
<property name="title"> <widget class="QPushButton" name="reset_frequencies_push_button">
<string>Frequency Calibration</string> <property name="text">
</property> <string>Reset</string>
<layout class="QFormLayout" name="formLayout_7"> </property>
<property name="fieldGrowthPolicy"> </widget>
<enum>QFormLayout::AllNonFixedFieldsGrow</enum> </item>
</property> <item>
<item row="0" column="0"> <spacer name="horizontalSpacer_6">
<widget class="QLabel" name="label_7"> <property name="orientation">
<property name="text"> <enum>Qt::Horizontal</enum>
<string>Intercept:</string> </property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="toolTip">
<string>See WSPR documentattion Appendix C for details of how to determine these factors for your radio.</string>
</property>
<property name="title">
<string>Frequency Calibration</string>
</property>
<layout class="QFormLayout" name="formLayout_7">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property> </property>
<property name="buddy"> <item row="0" column="0">
<cstring>calibration_intercept_spin_box</cstring> <widget class="QLabel" name="label_7">
</property> <property name="text">
</widget> <string>Intercept:</string>
</item> </property>
<item row="0" column="1"> <property name="buddy">
<widget class="QDoubleSpinBox" name="calibration_intercept_spin_box"> <cstring>calibration_intercept_spin_box</cstring>
<property name="alignment"> </property>
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </widget>
</property> </item>
<property name="suffix"> <item row="0" column="1">
<string> Hz</string> <widget class="QDoubleSpinBox" name="calibration_intercept_spin_box">
</property> <property name="alignment">
<property name="decimals"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<number>2</number> </property>
</property> <property name="suffix">
<property name="minimum"> <string> Hz</string>
<double>-99999.990000000005239</double> </property>
</property> <property name="decimals">
<property name="maximum"> <number>2</number>
<double>99999.990000000005239</double> </property>
</property> <property name="minimum">
<property name="singleStep"> <double>-99999.990000000005239</double>
<double>0.100000000000000</double> </property>
</property> <property name="maximum">
</widget> <double>99999.990000000005239</double>
</item> </property>
<item row="1" column="0"> <property name="singleStep">
<widget class="QLabel" name="label_8"> <double>0.100000000000000</double>
<property name="text"> </property>
<string>Slope:</string> </widget>
</property> </item>
<property name="buddy"> <item row="1" column="0">
<cstring>calibration_slope_ppm_spin_box</cstring> <widget class="QLabel" name="label_8">
</property> <property name="text">
</widget> <string>Slope:</string>
</item> </property>
<item row="1" column="1"> <property name="buddy">
<widget class="QDoubleSpinBox" name="calibration_slope_ppm_spin_box"> <cstring>calibration_slope_ppm_spin_box</cstring>
<property name="alignment"> </property>
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </widget>
</property> </item>
<property name="suffix"> <item row="1" column="1">
<string> ppm</string> <widget class="QDoubleSpinBox" name="calibration_slope_ppm_spin_box">
</property> <property name="alignment">
<property name="decimals"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<number>4</number> </property>
</property> <property name="suffix">
<property name="minimum"> <string> ppm</string>
<double>-999.999900000000025</double> </property>
</property> <property name="decimals">
<property name="maximum"> <number>4</number>
<double>999.999900000000025</double> </property>
</property> <property name="minimum">
<property name="singleStep"> <double>-999.999900000000025</double>
<double>0.100000000000000</double> </property>
</property> <property name="maximum">
<property name="value"> <double>999.999900000000025</double>
<double>0.000000000000000</double> </property>
</property> <property name="singleStep">
</widget> <double>0.100000000000000</double>
</item> </property>
</layout> <property name="value">
</widget> <double>0.000000000000000</double>
</item> </property>
<item row="0" column="3"> </widget>
<spacer name="horizontalSpacer_6"> </item>
<property name="orientation"> </layout>
<enum>Qt::Horizontal</enum> </widget>
</property> </item>
<property name="sizeHint" stdset="0"> <item>
<size> <spacer name="verticalSpacer_6">
<width>40</width> <property name="orientation">
<height>20</height> <enum>Qt::Vertical</enum>
</size> </property>
</property> <property name="sizeHint" stdset="0">
</spacer> <size>
</item> <width>20</width>
<item row="1" column="2"> <height>40</height>
<spacer name="verticalSpacer_6"> </size>
<property name="orientation"> </property>
<enum>Qt::Vertical</enum> </spacer>
</property> </item>
<property name="sizeHint" stdset="0"> </layout>
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1992,6 +2013,9 @@ Right click for insert and delete options.</string>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection"> <attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool> <bool>true</bool>
</attribute> </attribute>
@ -2274,6 +2298,7 @@ soundcard changes</string>
<tabstop>udpWindowToFront</tabstop> <tabstop>udpWindowToFront</tabstop>
<tabstop>udpWindowRestore</tabstop> <tabstop>udpWindowRestore</tabstop>
<tabstop>frequencies_table_view</tabstop> <tabstop>frequencies_table_view</tabstop>
<tabstop>reset_frequencies_push_button</tabstop>
<tabstop>calibration_intercept_spin_box</tabstop> <tabstop>calibration_intercept_spin_box</tabstop>
<tabstop>calibration_slope_ppm_spin_box</tabstop> <tabstop>calibration_slope_ppm_spin_box</tabstop>
<tabstop>stations_table_view</tabstop> <tabstop>stations_table_view</tabstop>
@ -2351,12 +2376,12 @@ soundcard changes</string>
</connection> </connection>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="split_mode_button_group"/> <buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="TX_mode_button_group"/> <buttongroup name="TX_mode_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="PTT_method_button_group"/>
</buttongroups> </buttongroups>
</ui> </ui>

View File

@ -4,15 +4,24 @@
#include "CandidateKeyFilter.hpp" #include "CandidateKeyFilter.hpp"
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referencing_model ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel * referenced_model
, QAbstractItemModel * referenced_model
, int referencing_key_column
, int referenced_key_column , int referenced_key_column
, QObject * parent , QObject * parent
, int referencing_key_role
, int referenced_key_role) , int referenced_key_role)
: QStyledItemDelegate {parent} : QStyledItemDelegate {parent}
, candidate_key_filter_ {new CandidateKeyFilter {referencing_model, referenced_model, referencing_key_column, referenced_key_column, referencing_key_role, referenced_key_role}} , candidate_key_filter_ {new CandidateKeyFilter {referenced_model, referenced_key_column, nullptr, referenced_key_role}}
{
}
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent
, int referenced_key_role
, int referencing_key_role)
: QStyledItemDelegate {parent}
, candidate_key_filter_ {new CandidateKeyFilter {referenced_model, referencing_model, referenced_key_column, referencing_key_column, nullptr, referenced_key_role, referencing_key_role}}
{ {
} }

View File

@ -17,13 +17,20 @@ class ForeignKeyDelegate final
: public QStyledItemDelegate : public QStyledItemDelegate
{ {
public: public:
explicit ForeignKeyDelegate (QAbstractItemModel const * referencing_model // many to many relationship
, QAbstractItemModel * referenced_model explicit ForeignKeyDelegate (QAbstractItemModel * referenced_model
, int referencing_key_column = 0 , int referenced_key_column
, int referenced_key_column = 0
, QObject * parent = nullptr , QObject * parent = nullptr
, int referencing_key_role = Qt::EditRole
, int referenced_key_role = Qt::EditRole); , int referenced_key_role = Qt::EditRole);
// one to many (referenced to referencing) relationship
explicit ForeignKeyDelegate (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent = nullptr
, int referenced_key_role = Qt::EditRole
, int referencing_key_role = Qt::EditRole);
~ForeignKeyDelegate (); ~ForeignKeyDelegate ();
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;

View File

@ -1,15 +1,6 @@
#include "FrequencyItemDelegate.hpp" #include "FrequencyItemDelegate.hpp"
#include "Radio.hpp"
#include "FrequencyLineEdit.hpp" #include "FrequencyLineEdit.hpp"
#include "Bands.hpp"
QString FrequencyItemDelegate::displayText (QVariant const& value, QLocale const& locale) const
{
auto frequency = value.value<Radio::Frequency> ();
auto band_name = bands_->data (bands_->find (frequency));
return Radio::pretty_frequency_MHz_string (frequency, locale) + " MHz (" + band_name.toString () + ')';
}
QWidget * FrequencyItemDelegate::createEditor (QWidget * parent QWidget * FrequencyItemDelegate::createEditor (QWidget * parent
, QStyleOptionViewItem const& /* option */ , QStyleOptionViewItem const& /* option */
@ -21,11 +12,6 @@ QWidget * FrequencyItemDelegate::createEditor (QWidget * parent
} }
QString FrequencyDeltaItemDelegate::displayText (QVariant const& value, QLocale const& locale) const
{
return Radio::pretty_frequency_MHz_string (value.value<Radio::FrequencyDelta> (), locale) + " MHz";
}
QWidget * FrequencyDeltaItemDelegate::createEditor (QWidget * parent QWidget * FrequencyDeltaItemDelegate::createEditor (QWidget * parent
, QStyleOptionViewItem const& /* option */ , QStyleOptionViewItem const& /* option */
, QModelIndex const& /* index */) const , QModelIndex const& /* index */) const

View File

@ -1,53 +1,45 @@
#ifndef FREQUENCY_ITEM_DELEGATE_HPP_ #ifndef FREQUENCY_ITEM_DELEGATE_HPP_
#define FREQUENCY_ITEM_DELEGATE_HPP_ #define FREQUENCY_ITEM_DELEGATE_HPP_
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
class Bands; //
// Class FrequencyItemDelegate
// //
// Class FrequencyItemDelegate // Item delegate for displaying and editing a Frequency item in a
// // view that uses a FrequencyLineEdit as an item delegate for the
// Item delegate for displaying and editing a Frequency item in a // edit role.
// view that uses a FrequencyLineEdit as an item delegate for the //
// edit role. class FrequencyItemDelegate final
// : public QStyledItemDelegate
class FrequencyItemDelegate final {
: public QStyledItemDelegate public:
{ explicit FrequencyItemDelegate (QObject * parent = nullptr)
public: : QStyledItemDelegate {parent}
explicit FrequencyItemDelegate (Bands const * bands, QObject * parent = nullptr) {
: QStyledItemDelegate {parent} }
, bands_ {bands}
{ QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
} };
QString displayText (QVariant const& value, QLocale const&) const override;
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; //
// Class FrequencyDeltaItemDelegate
private: //
Bands const * bands_; // Item delegate for displaying and editing a FrequencyDelta item
}; // in a view that uses a FrequencyDeltaLineEdit as an item
// delegate for the edit role.
//
// class FrequencyDeltaItemDelegate final
// Class FrequencyDeltaItemDelegate : public QStyledItemDelegate
// {
// Item delegate for displaying and editing a FrequencyDelta item public:
// in a view that uses a FrequencyDeltaLineEdit as an item explicit FrequencyDeltaItemDelegate (QObject * parent = nullptr)
// delegate for the edit role. : QStyledItemDelegate {parent}
// {
class FrequencyDeltaItemDelegate final }
: public QStyledItemDelegate
{ QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
public: };
explicit FrequencyDeltaItemDelegate (QObject * parent = nullptr)
: QStyledItemDelegate {parent} #endif
{
}
QString displayText (QVariant const& value, QLocale const&) const override;
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
};
#endif

View File

@ -11,25 +11,120 @@
#include <QMimeData> #include <QMimeData>
#include <QDataStream> #include <QDataStream>
#include <QByteArray> #include <QByteArray>
#include <QDebug>
#include "Bands.hpp"
#include "pimpl_impl.hpp" #include "pimpl_impl.hpp"
namespace
{
FrequencyList::FrequencyItems const default_frequency_list =
{
{136000, Modes::WSPR},
{136130, Modes::JT65},
{474200, Modes::JT65},
{474200, Modes::JT9},
{474200, Modes::WSPR},
{1836600, Modes::WSPR},
{1838000, Modes::JT65},
{1840000, Modes::JT9},
{3576000, Modes::JT65},
{3578000, Modes::JT9},
{3559260, Modes::WSPR},
{5357000, Modes::JT65},
{5287200, Modes::WSPR},
{7038600, Modes::WSPR},
{7076000, Modes::JT65},
{7078000, Modes::JT9},
{10138000, Modes::JT65},
{10138700, Modes::WSPR},
{10140000, Modes::JT9},
{14095600, Modes::WSPR},
{14076000, Modes::JT65},
{14078000, Modes::JT9},
{18102000, Modes::JT65},
{18104000, Modes::JT9},
{18104460, Modes::WSPR},
{21076000, Modes::JT65},
{21078000, Modes::JT9},
{21094600, Modes::WSPR},
{24917000, Modes::JT65},
{24919000, Modes::JT9},
{24924600, Modes::WSPR},
{28076000, Modes::JT65},
{28078000, Modes::JT9},
{28124600, Modes::WSPR},
{50276000, Modes::JT65},
{50293000, Modes::WSPR},
{70091000, Modes::JT65},
{70091000, Modes::WSPR},
{144000000, Modes::JT4},
{144489000, Modes::JT65},
{144489000, Modes::WSPR},
{222000000, Modes::JT4},
{222000000, Modes::JT65},
{432000000, Modes::JT4},
{432000000, Modes::JT65},
{432300000, Modes::WSPR},
{902000000, Modes::JT4},
{902000000, Modes::JT65},
{1296000000, Modes::JT4},
{1296000000, Modes::JT65},
{1296500000, Modes::WSPR},
{2301000000, Modes::JT4},
{2301000000, Modes::JT65},
{2304000000, Modes::JT4},
{2304000000, Modes::JT65},
{2320000000, Modes::JT4},
{2320000000, Modes::JT65},
{3400000000, Modes::JT4},
{3400000000, Modes::JT65},
{3456000000, Modes::JT4},
{3456000000, Modes::JT65},
{5760000000, Modes::JT4},
{5760000000, Modes::JT65},
{10368000000, Modes::JT4},
{10368000000, Modes::JT65},
{24048000000, Modes::JT4},
{24048000000, Modes::JT65},
};
}
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug debug, FrequencyList::Item const& item)
{
debug.nospace () << "FrequencyItem("
<< item.frequency_ << ", "
<< item.mode_ << ')';
return debug.space ();
}
#endif
QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item)
{
return os << item.frequency_
<< item.mode_;
}
QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item)
{
return is >> item.frequency_
>> item.mode_;
}
class FrequencyList::impl final class FrequencyList::impl final
: public QAbstractTableModel : public QAbstractTableModel
{ {
public: public:
impl (Frequencies frequencies, QObject * parent) impl (Bands const * bands, QObject * parent)
: QAbstractTableModel {parent} : QAbstractTableModel {parent}
, frequencies_ {frequencies} , bands_ {bands}
, mode_filter_ {Modes::NULL_MODE}
{ {
} }
Frequencies const& frequencies () const {return frequencies_;} FrequencyItems frequency_list (FrequencyItems);
void assign (Frequencies); QModelIndex add (Item);
QModelIndex add (Frequency);
protected:
// Implement the QAbstractTableModel interface // Implement the QAbstractTableModel interface
int rowCount (QModelIndex const& parent = QModelIndex {}) const override; int rowCount (QModelIndex const& parent = QModelIndex {}) const override;
int columnCount (QModelIndex const& parent = QModelIndex {}) const override; int columnCount (QModelIndex const& parent = QModelIndex {}) const override;
@ -42,21 +137,17 @@ protected:
QStringList mimeTypes () const override; QStringList mimeTypes () const override;
QMimeData * mimeData (QModelIndexList const&) const override; QMimeData * mimeData (QModelIndexList const&) const override;
private: static int constexpr num_cols {3};
static int constexpr num_cols {2};
static auto constexpr mime_type ="application/wsjt.Frequencies"; static auto constexpr mime_type ="application/wsjt.Frequencies";
Frequencies frequencies_; Bands const * bands_;
FrequencyItems frequency_list_;
Mode mode_filter_;
}; };
FrequencyList::FrequencyList (QObject * parent) FrequencyList::FrequencyList (Bands const * bands, QObject * parent)
: FrequencyList {{}, parent}
{
}
FrequencyList::FrequencyList (Frequencies frequencies, QObject * parent)
: QSortFilterProxyModel {parent} : QSortFilterProxyModel {parent}
, m_ {frequencies, parent} , m_ {bands, parent}
{ {
setSourceModel (&*m_); setSourceModel (&*m_);
setSortRole (SortRole); setSortRole (SortRole);
@ -66,25 +157,52 @@ FrequencyList::~FrequencyList ()
{ {
} }
FrequencyList& FrequencyList::operator = (Frequencies frequencies) auto FrequencyList::frequency_list (FrequencyItems frequency_list) -> FrequencyItems
{ {
m_->assign (frequencies); return m_->frequency_list (frequency_list);
return *this;
} }
auto FrequencyList::frequencies () const -> Frequencies auto FrequencyList::frequency_list () const -> FrequencyItems const&
{ {
return m_->frequencies (); return m_->frequency_list_;
} }
QModelIndex FrequencyList::add (Frequency f) QModelIndex FrequencyList::best_working_frequency (Frequency f, Mode mode) const
{
auto const& target_band = m_->bands_->find (f);
if (target_band != m_->bands_->out_of_band ())
{
// find a frequency in the same band that is allowed for the
// target mode
for (int row = 0; row < rowCount (); ++row)
{
auto const& source_row = mapToSource (index (row, 0)).row ();
auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_);
if (band->name_ == target_band->name_)
{
if (m_->frequency_list_[source_row].mode_ == mode)
{
return index (row, 0);
}
}
}
}
return QModelIndex {};
}
void FrequencyList::reset_to_defaults ()
{
m_->frequency_list (default_frequency_list);
}
QModelIndex FrequencyList::add (Item f)
{ {
return mapFromSource (m_->add (f)); return mapFromSource (m_->add (f));
} }
bool FrequencyList::remove (Frequency f) bool FrequencyList::remove (Item f)
{ {
auto row = m_->frequencies ().indexOf (f); auto row = m_->frequency_list_.indexOf (f);
if (0 > row) if (0 > row)
{ {
@ -123,38 +241,54 @@ bool FrequencyList::removeDisjointRows (QModelIndexList rows)
result = false; result = false;
} }
} }
return result;
}
void FrequencyList::filter (Mode mode)
{
m_->mode_filter_ = mode;
invalidateFilter ();
}
bool FrequencyList::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const
{
bool result {true};
if (m_->mode_filter_ != Modes::NULL_MODE)
{
auto const& item = m_->frequency_list_[source_row];
result = item.mode_ == Modes::NULL_MODE || m_->mode_filter_ == item.mode_;
}
return result; return result;
} }
void FrequencyList::impl::assign (Frequencies frequencies) auto FrequencyList::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems
{ {
beginResetModel (); beginResetModel ();
std::swap (frequencies_, frequencies); std::swap (frequency_list_, frequency_list);
endResetModel (); endResetModel ();
return frequency_list;
} }
QModelIndex FrequencyList::impl::add (Frequency f) QModelIndex FrequencyList::impl::add (Item f)
{ {
// Any Frequency that isn't in the list may be added // Any Frequency that isn't in the list may be added
if (!frequencies_.contains (f)) if (!frequency_list_.contains (f))
{ {
auto row = frequencies_.size (); auto row = frequency_list_.size ();
beginInsertRows (QModelIndex {}, row, row); beginInsertRows (QModelIndex {}, row, row);
frequencies_.append (f); frequency_list_.append (f);
endInsertRows (); endInsertRows ();
return index (row, 0); return index (row, 0);
} }
return QModelIndex {}; return QModelIndex {};
} }
int FrequencyList::impl::rowCount (QModelIndex const& parent) const int FrequencyList::impl::rowCount (QModelIndex const& parent) const
{ {
return parent.isValid () ? 0 : frequencies_.size (); return parent.isValid () ? 0 : frequency_list_.size ();
} }
int FrequencyList::impl::columnCount (QModelIndex const& parent) const int FrequencyList::impl::columnCount (QModelIndex const& parent) const
@ -165,26 +299,17 @@ int FrequencyList::impl::columnCount (QModelIndex const& parent) const
Qt::ItemFlags FrequencyList::impl::flags (QModelIndex const& index) const Qt::ItemFlags FrequencyList::impl::flags (QModelIndex const& index) const
{ {
auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled;
auto row = index.row (); auto row = index.row ();
auto column = index.column (); auto column = index.column ();
if (index.isValid () if (index.isValid ()
&& row < frequencies_.size () && row < frequency_list_.size ()
&& column < num_cols) && column < num_cols)
{ {
switch (column) if (frequency_mhz_column != column)
{ {
case 0: result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
break;
case 1:
result |= Qt::ItemIsDragEnabled;
break;
} }
} }
return result; return result;
} }
@ -192,25 +317,51 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const
{ {
QVariant item; QVariant item;
auto row = index.row (); auto const& row = index.row ();
auto column = index.column (); auto const& column = index.column ();
if (index.isValid () if (index.isValid ()
&& row < frequencies_.size () && row < frequency_list_.size ()
&& column < num_cols) && column < num_cols)
{ {
auto frequency = frequencies_.at (row); auto const& frequency_item = frequency_list_.at (row);
switch (column) switch (column)
{ {
case 0: case mode_column:
switch (role) switch (role)
{ {
case SortRole: case SortRole:
case Qt::DisplayRole: case Qt::DisplayRole:
case Qt::EditRole: case Qt::EditRole:
case Qt::AccessibleTextRole: case Qt::AccessibleTextRole:
item = frequency; item = Modes::name (frequency_item.mode_);
break;
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("Mode");
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
break;
case frequency_column:
switch (role)
{
case SortRole:
case Qt::EditRole:
case Qt::AccessibleTextRole:
item = frequency_item.frequency_;
break;
case Qt::DisplayRole:
{
auto const& band = bands_->find (frequency_item.frequency_);
item = Radio::pretty_frequency_MHz_string (frequency_item.frequency_) + " MHz (" + band->name_ + ')';
}
break; break;
case Qt::ToolTipRole: case Qt::ToolTipRole:
@ -224,22 +375,24 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const
} }
break; break;
case 1: case frequency_mhz_column:
switch (role) switch (role)
{ {
case Qt::DisplayRole:
case Qt::EditRole: case Qt::EditRole:
case Qt::AccessibleTextRole: case Qt::AccessibleTextRole:
item = static_cast<double> (frequency / 1.e6); item = frequency_item.frequency_ / 1.e6;
break; break;
case SortRole: // use the underlying Frequency value case Qt::DisplayRole:
item = frequency; {
auto const& band = bands_->find (frequency_item.frequency_);
item = Radio::pretty_frequency_MHz_string (frequency_item.frequency_) + " MHz (" + band->name_ + ')';
}
break; break;
case Qt::ToolTipRole: case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole: case Qt::AccessibleDescriptionRole:
item = tr ("Frequency MHz"); item = tr ("Frequency (MHz)");
break; break;
case Qt::TextAlignmentRole: case Qt::TextAlignmentRole:
@ -249,7 +402,6 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const
break; break;
} }
} }
return item; return item;
} }
@ -257,21 +409,44 @@ bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant cons
{ {
bool changed {false}; bool changed {false};
auto row = model_index.row (); auto const& row = model_index.row ();
if (model_index.isValid () if (model_index.isValid ()
&& Qt::EditRole == role && Qt::EditRole == role
&& row < frequencies_.size () && row < frequency_list_.size ())
&& 0 == model_index.column ()
&& value.canConvert<Frequency> ())
{ {
auto frequency = value.value<Frequency> (); QVector<int> roles;
auto original_frequency = frequencies_.at (row); roles << role;
if (frequency != original_frequency)
auto& item = frequency_list_[row];
switch (model_index.column ())
{ {
frequencies_.replace (row, frequency); case mode_column:
Q_EMIT dataChanged (model_index, index (model_index.row (), 1), QVector<int> {} << role); if (value.canConvert<Mode> ())
{
auto mode = Modes::value (value.toString ());
if (mode != item.mode_)
{
item.mode_ = mode;
Q_EMIT dataChanged (model_index, model_index, roles);
changed = true;
}
}
break;
case frequency_column:
if (value.canConvert<Frequency> ())
{
auto frequency = value.value<Frequency> ();
if (frequency != item.frequency_)
{
item.frequency_ = frequency;
// mark derived column (1) changed as well
Q_EMIT dataChanged (index (model_index.row (), 1), model_index, roles);
changed = true;
}
}
break;
} }
changed = true;
} }
return changed; return changed;
@ -280,22 +455,21 @@ bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant cons
QVariant FrequencyList::impl::headerData (int section, Qt::Orientation orientation, int role) const QVariant FrequencyList::impl::headerData (int section, Qt::Orientation orientation, int role) const
{ {
QVariant header; QVariant header;
if (Qt::DisplayRole == role if (Qt::DisplayRole == role
&& Qt::Horizontal == orientation && Qt::Horizontal == orientation
&& section < num_cols) && section < num_cols)
{ {
switch (section) switch (section)
{ {
case 0: header = tr ("Frequency"); break; case mode_column: header = tr ("Mode"); break;
case 1: header = tr ("Frequency (MHz)"); break; case frequency_column: header = tr ("Frequency"); break;
case frequency_mhz_column: header = tr ("Frequency (MHz)"); break;
} }
} }
else else
{ {
header = QAbstractTableModel::headerData (section, orientation, role); header = QAbstractTableModel::headerData (section, orientation, role);
} }
return header; return header;
} }
@ -306,12 +480,11 @@ bool FrequencyList::impl::removeRows (int row, int count, QModelIndex const& par
beginRemoveRows (parent, row, row + count - 1); beginRemoveRows (parent, row, row + count - 1);
for (auto r = 0; r < count; ++r) for (auto r = 0; r < count; ++r)
{ {
frequencies_.removeAt (row); frequency_list_.removeAt (row);
} }
endRemoveRows (); endRemoveRows ();
return true; return true;
} }
return false; return false;
} }
@ -322,12 +495,11 @@ bool FrequencyList::impl::insertRows (int row, int count, QModelIndex const& par
beginInsertRows (parent, row, row + count - 1); beginInsertRows (parent, row, row + count - 1);
for (auto r = 0; r < count; ++r) for (auto r = 0; r < count; ++r)
{ {
frequencies_.insert (row, Frequency {}); frequency_list_.insert (row, Item {0, Mode::NULL_MODE});
} }
endInsertRows (); endInsertRows ();
return true; return true;
} }
return false; return false;
} }
@ -346,7 +518,7 @@ QMimeData * FrequencyList::impl::mimeData (QModelIndexList const& items) const
Q_FOREACH (auto const& item, items) Q_FOREACH (auto const& item, items)
{ {
if (item.isValid ()) if (item.isValid () && frequency_column == item.column ())
{ {
stream << QString {data (item, Qt::DisplayRole).toString ()}; stream << QString {data (item, Qt::DisplayRole).toString ()};
} }

View File

@ -3,9 +3,13 @@
#include "pimpl_h.hpp" #include "pimpl_h.hpp"
#include <QList>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include "Radio.hpp" #include "Radio.hpp"
#include "Modes.hpp"
class Bands;
// //
// Class FrequencyList // Class FrequencyList
@ -31,23 +35,45 @@
class FrequencyList final class FrequencyList final
: public QSortFilterProxyModel : public QSortFilterProxyModel
{ {
Q_OBJECT;
public: public:
using Frequency = Radio::Frequency; using Frequency = Radio::Frequency;
using Frequencies = Radio::Frequencies; using Mode = Modes::Mode;
explicit FrequencyList (QObject * parent = nullptr); struct Item
explicit FrequencyList (Frequencies, QObject * parent = nullptr); {
Frequency frequency_;
Mode mode_;
};
using FrequencyItems = QList<Item>;
enum Column {mode_column, frequency_column, frequency_mhz_column};
explicit FrequencyList (Bands const *, QObject * parent = nullptr);
~FrequencyList (); ~FrequencyList ();
// Load and store contents // Load and store contents
FrequencyList& operator = (Frequencies); FrequencyItems frequency_list (FrequencyItems);
Frequencies frequencies () const; FrequencyItems const& frequency_list () const;
// Find nearest best working frequency given a frequency and mode
QModelIndex best_working_frequency (Frequency, Mode) const;
// Set filter
void filter (Mode);
// Reset
Q_SLOT void reset_to_defaults ();
// Model API // Model API
QModelIndex add (Frequency); QModelIndex add (Item);
bool remove (Frequency); bool remove (Item);
bool removeDisjointRows (QModelIndexList); bool removeDisjointRows (QModelIndexList);
// Proxy API
bool filterAcceptsRow (int source_row, QModelIndex const& parent) const override;
// Custom roles. // Custom roles.
static int constexpr SortRole = Qt::UserRole; static int constexpr SortRole = Qt::UserRole;
@ -56,4 +82,22 @@ private:
pimpl<impl> m_; pimpl<impl> m_;
}; };
inline
bool operator == (FrequencyList::Item const& lhs, FrequencyList::Item const& rhs)
{
return
lhs.frequency_ == rhs.frequency_
&& lhs.mode_ == rhs.mode_;
}
QDataStream& operator << (QDataStream&, FrequencyList::Item const&);
QDataStream& operator >> (QDataStream&, FrequencyList::Item&);
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug, FrequencyList::Item const&);
#endif
Q_DECLARE_METATYPE (FrequencyList::Item);
Q_DECLARE_METATYPE (FrequencyList::FrequencyItems);
#endif #endif

View File

@ -1,92 +1,87 @@
#include "LiveFrequencyValidator.hpp" #include "LiveFrequencyValidator.hpp"
#include <QLocale> #include <QLocale>
#include <QString> #include <QString>
#include <QComboBox> #include <QComboBox>
#include <QLineEdit> #include <QLineEdit>
#include "Bands.hpp" #include "Bands.hpp"
#include "FrequencyList.hpp" #include "FrequencyList.hpp"
#include "moc_LiveFrequencyValidator.cpp" #include "moc_LiveFrequencyValidator.cpp"
LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box
, Bands const * bands , Bands const * bands
, FrequencyList const * frequencies , FrequencyList const * frequencies
, QWidget * parent) , QWidget * parent)
: QRegExpValidator { : QRegExpValidator {
QRegExp { // frequency in MHz or band QRegExp { // frequency in MHz or band
bands->data (QModelIndex {}).toString () // out of band string bands->data (QModelIndex {}).toString () // out of band string
+ QString {R"(|((\d{0,6}(\)"} // up to 6 digits + QString {R"(|((\d{0,6}(\)"} // or up to 6 digits
+ QLocale {}.decimalPoint () // (followed by decimal separator + QLocale {}.decimalPoint () // (followed by decimal separator
+ R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,4}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive)) + R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,4}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive))
+ QLocale {}.decimalPoint () // or a decimal separator + QLocale {}.decimalPoint () // or a decimal separator
+ R"(\d{0,6})?))" // followed by up to 6 digits + R"(\d{0,6})?))" // followed by up to 6 digits
} }
, parent , parent
} }
, bands_ {bands} , bands_ {bands}
, frequencies_ {frequencies} , frequencies_ {frequencies}
, combo_box_ {combo_box} , combo_box_ {combo_box}
{ {
} }
auto LiveFrequencyValidator::validate (QString& input, int& pos) const -> State auto LiveFrequencyValidator::validate (QString& input, int& pos) const -> State
{ {
auto state = QRegExpValidator::validate (input, pos); auto state = QRegExpValidator::validate (input, pos);
// by never being Acceptable we force fixup calls on ENTER or
// by never being Acceptable we force fixup calls on ENTER or // losing focus
// losing focus return Acceptable == state ? Intermediate : state;
return Acceptable == state ? Intermediate : state; }
}
void LiveFrequencyValidator::fixup (QString& input) const
void LiveFrequencyValidator::fixup (QString& input) const {
{ QRegExpValidator::fixup (input);
QRegExpValidator::fixup (input); auto const& out_of_band = bands_->out_of_band ();
if (!QString {out_of_band->name_}.startsWith (input))
auto out_of_band = bands_->data (QModelIndex {}).toString (); {
if (input.contains ('m', Qt::CaseInsensitive))
if (!out_of_band.startsWith (input)) {
{ input = input.toLower ();
if (input.contains ('m', Qt::CaseInsensitive))
{ QVector<QVariant> frequencies;
input = input.toLower (); Q_FOREACH (auto const& item, frequencies_->frequency_list ())
{
QVector<QVariant> frequencies; if (bands_->find (item.frequency_)->name_ == input)
for (int r = 0; r < frequencies_->rowCount (); ++r) {
{ frequencies << item.frequency_;
auto frequency = frequencies_->index (r, 0).data (); }
auto band_index = bands_->find (frequency); }
if (band_index.data ().toString () == input) if (!frequencies.isEmpty ())
{ {
frequencies << frequency; Q_EMIT valid (frequencies.first ().value<Frequency> ());
} }
} else
if (!frequencies.isEmpty ()) {
{ input = QString {};
Q_EMIT valid (frequencies.first ().value<Frequency> ()); }
} }
else else
{ {
input = QString {}; // frequency input
} auto f = Radio::frequency (input, 6);
} input = bands_->find (f)->name_;
else Q_EMIT valid (f);
{ }
// frequency input
auto f = Radio::frequency (input, 6); if (bands_->out_of_band ()->name_ == input)
input = bands_->data (bands_->find (f)).toString (); {
Q_EMIT valid (f); combo_box_->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}");
} }
else
if (out_of_band == input) {
{ combo_box_->lineEdit ()->setStyleSheet ({});
combo_box_->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); }
} combo_box_->setCurrentText (input);
else }
{ }
combo_box_->lineEdit ()->setStyleSheet ({});
}
combo_box_->setCurrentText (input);
}
}

72
MetaDataRegistry.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "MetaDataRegistry.hpp"
#include <QMetaType>
#include <QItemEditorFactory>
#include <QStandardItemEditorCreator>
#include "Radio.hpp"
#include "FrequencyList.hpp"
#include "AudioDevice.hpp"
#include "Configuration.hpp"
#include "StationList.hpp"
#include "Transceiver.hpp"
#include "TransceiverFactory.hpp"
#include "WFPalette.hpp"
#include "FrequencyLineEdit.hpp"
void register_types ()
{
// Default custom item view delegates
auto factory = new QItemEditorFactory;
// Radio namespace
auto frequency_type_id = qRegisterMetaType<Radio::Frequency> ("Frequency");
factory->registerEditor (frequency_type_id, new QStandardItemEditorCreator<FrequencyLineEdit> ());
auto frequency_delta_type_id = qRegisterMetaType<Radio::FrequencyDelta> ("FrequencyDelta");
factory->registerEditor (frequency_delta_type_id, new QStandardItemEditorCreator<FrequencyDeltaLineEdit> ());
// Frequency list model
qRegisterMetaType<FrequencyList::Item> ("Item");
qRegisterMetaTypeStreamOperators<FrequencyList::Item> ("Item");
qRegisterMetaType<FrequencyList::FrequencyItems> ("FrequencyItems");
qRegisterMetaTypeStreamOperators<FrequencyList::FrequencyItems> ("FrequencyItems");
// Audio device
qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel");
// Configuration
qRegisterMetaType<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaType<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
// Station details
qRegisterMetaType<StationList::Station> ("Station");
qRegisterMetaTypeStreamOperators<StationList::Station> ("Station");
qRegisterMetaType<StationList::Stations> ("Stations");
qRegisterMetaTypeStreamOperators<StationList::Stations> ("Stations");
// Transceiver
qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState");
qRegisterMetaType<Transceiver::MODE> ("Transceiver::MODE");
// Transceiver factory
qRegisterMetaType<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits");
qRegisterMetaType<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaType<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
qRegisterMetaType<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod");
qRegisterMetaTypeStreamOperators<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod");
qRegisterMetaType<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource");
qRegisterMetaTypeStreamOperators<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource");
qRegisterMetaType<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode");
qRegisterMetaTypeStreamOperators<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode");
// Waterfall palette
qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours");
QItemEditorFactory::setDefaultFactory (factory);
}

6
MetaDataRegistry.hpp Normal file
View File

@ -0,0 +1,6 @@
#ifndef META_DATA_REGISTRY_HPP__
#define META_DATA_REGISTRY_HPP__
void register_types ();
#endif

92
Modes.cpp Normal file
View File

@ -0,0 +1,92 @@
#include "Modes.hpp"
#include <QString>
#include <QVariant>
namespace
{
char const * const mode_names[] =
{
"",
"JT65",
"JT9",
"JT9W-1",
"JT4",
"WSPR",
};
}
Modes::Modes (QObject * parent)
: QAbstractListModel {parent}
{
}
char const * Modes::name (Mode m)
{
return mode_names[static_cast<int> (m)];
}
auto Modes::value (QString const& s) -> Mode
{
auto end = mode_names + sizeof (mode_names) / sizeof (mode_names[0]);
auto p = std::find_if (mode_names, end
, [&s] (char const * const name) {
return name == s;
});
return p != end ? static_cast<Mode> (p - mode_names) : NULL_MODE;
}
QVariant Modes::data (QModelIndex const& index, int role) const
{
QVariant item;
if (index.isValid ())
{
auto const& row = index.row ();
switch (role)
{
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("Mode");
break;
case Qt::EditRole:
item = static_cast<Mode> (row);
break;
case Qt::DisplayRole:
case Qt::AccessibleTextRole:
item = mode_names[row];
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
}
return item;
}
QVariant Modes::headerData (int section, Qt::Orientation orientation, int role) const
{
QVariant result;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
result = tr ("Mode");
}
else
{
result = QAbstractListModel::headerData (section, orientation, role);
}
return result;
}
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Modes, Mode);
#endif
ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode);
ENUM_CONVERSION_OPS_IMPL (Modes, Mode);

49
Modes.hpp Normal file
View File

@ -0,0 +1,49 @@
#ifndef MODES_HPP__
#define MODES_HPP__
#include <QAbstractListModel>
#include "qt_helpers.hpp"
class Modes final
: public QAbstractListModel
{
Q_OBJECT;
Q_ENUMS (Mode);
public:
enum Mode
{
NULL_MODE,
JT65,
JT9,
JT9W_1,
JT4,
WSPR,
};
explicit Modes (QObject * parent = nullptr);
static char const * name (Mode);
static Mode value (QString const&);
// Implement the QAbstractListModel interface
int rowCount (QModelIndex const& parent = QModelIndex {}) const override
{
return parent.isValid () ? 0 : 6; // the number of modes in the
// Mode enumeration class
}
QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override;
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
};
Q_DECLARE_METATYPE (Modes::Mode);
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (Modes, Mode);
#endif
ENUM_QDATASTREAM_OPS_DECL (Modes, Mode);
ENUM_CONVERSION_OPS_DECL (Modes, Mode);
#endif

View File

@ -2,7 +2,6 @@
#include <cmath> #include <cmath>
#include <QMetaType>
#include <QString> #include <QString>
#include <QChar> #include <QChar>
#include <QDebug> #include <QDebug>
@ -14,19 +13,6 @@ namespace Radio
{ {
namespace namespace
{ {
struct init
{
init ()
{
qRegisterMetaType<Frequency> ("Frequency");
qRegisterMetaType<Frequencies> ("Frequencies");
qRegisterMetaTypeStreamOperators<Frequencies> ("Frequencies");
qRegisterMetaType<FrequencyDelta> ("FrequencyDelta");
}
} static_initaializer;
double constexpr MHz_factor {1.e6}; double constexpr MHz_factor {1.e6};
int constexpr frequency_precsion {6}; int constexpr frequency_precsion {6};

View File

@ -3,7 +3,6 @@
#include <QObject> #include <QObject>
#include <QLocale> #include <QLocale>
#include <QList>
class QVariant; class QVariant;
class QString; class QString;
@ -18,7 +17,6 @@ namespace Radio
// Frequency types // Frequency types
// //
using Frequency = quint64; using Frequency = quint64;
using Frequencies = QList<Frequency>;
using FrequencyDelta = qint64; using FrequencyDelta = qint64;
// //
@ -48,7 +46,6 @@ namespace Radio
} }
Q_DECLARE_METATYPE (Radio::Frequency); Q_DECLARE_METATYPE (Radio::Frequency);
Q_DECLARE_METATYPE (Radio::Frequencies);
Q_DECLARE_METATYPE (Radio::FrequencyDelta); Q_DECLARE_METATYPE (Radio::FrequencyDelta);
#endif #endif

View File

@ -19,20 +19,6 @@
#include "Bands.hpp" #include "Bands.hpp"
namespace
{
struct init
{
init ()
{
qRegisterMetaType<StationList::Station> ("Station");
qRegisterMetaTypeStreamOperators<StationList::Station> ("Station");
qRegisterMetaType<StationList::Stations> ("Stations");
qRegisterMetaTypeStreamOperators<StationList::Stations> ("Stations");
}
} static_initializer;
}
#if !defined (QT_NO_DEBUG_STREAM) #if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug debug, StationList::Station const& station) QDebug operator << (QDebug debug, StationList::Station const& station)
{ {
@ -70,12 +56,10 @@ public:
{ {
} }
Stations const& stations () const {return stations_;} Stations station_list (Stations);
void assign (Stations);
QModelIndex add (Station); QModelIndex add (Station);
FrequencyDelta offset (Frequency) const; FrequencyDelta offset (Frequency) const;
protected:
// Implement the QAbstractTableModel interface. // Implement the QAbstractTableModel interface.
int rowCount (QModelIndex const& parent = QModelIndex {}) const override; int rowCount (QModelIndex const& parent = QModelIndex {}) const override;
int columnCount (QModelIndex const& parent = QModelIndex {}) const override; int columnCount (QModelIndex const& parent = QModelIndex {}) const override;
@ -90,7 +74,6 @@ protected:
QMimeData * mimeData (QModelIndexList const&) const override; QMimeData * mimeData (QModelIndexList const&) const override;
bool dropMimeData (QMimeData const *, Qt::DropAction, int row, int column, QModelIndex const& parent) override; bool dropMimeData (QMimeData const *, Qt::DropAction, int row, int column, QModelIndex const& parent) override;
private:
// Helper method for band validation. // Helper method for band validation.
QModelIndex first_matching_band (QString const& band_name) const QModelIndex first_matching_band (QString const& band_name) const
{ {
@ -127,15 +110,14 @@ StationList::~StationList ()
{ {
} }
StationList& StationList::operator = (Stations stations) auto StationList::station_list (Stations stations) -> Stations
{ {
m_->assign (stations); return m_->station_list (stations);
return *this;
} }
auto StationList::stations () const -> Stations auto StationList::station_list () const -> Stations const&
{ {
return m_->stations (); return m_->stations_;
} }
QModelIndex StationList::add (Station s) QModelIndex StationList::add (Station s)
@ -145,13 +127,11 @@ QModelIndex StationList::add (Station s)
bool StationList::remove (Station s) bool StationList::remove (Station s)
{ {
auto row = m_->stations ().indexOf (s); auto row = m_->stations_.indexOf (s);
if (0 > row) if (0 > row)
{ {
return false; return false;
} }
return removeRow (row); return removeRow (row);
} }
@ -194,11 +174,12 @@ auto StationList::offset (Frequency f) const -> FrequencyDelta
} }
void StationList::impl::assign (Stations stations) auto StationList::impl::station_list (Stations stations) -> Stations
{ {
beginResetModel (); beginResetModel ();
std::swap (stations_, stations); std::swap (stations_, stations);
endResetModel (); endResetModel ();
return stations;
} }
QModelIndex StationList::impl::add (Station s) QModelIndex StationList::impl::add (Station s)
@ -221,22 +202,19 @@ QModelIndex StationList::impl::add (Station s)
auto StationList::impl::offset (Frequency f) const -> FrequencyDelta auto StationList::impl::offset (Frequency f) const -> FrequencyDelta
{ {
// Lookup band for frequency // Lookup band for frequency
auto band_index = bands_->find (f); auto const& band = bands_->find (f);
if (band_index.isValid ()) if (band != bands_->out_of_band ())
{ {
auto band_name = band_index.data ().toString ();
// Lookup station for band // Lookup station for band
for (int i = 0; i < stations ().size (); ++i) for (int i = 0; i < stations_.size (); ++i)
{ {
if (stations_[i].band_name_ == band_name) if (stations_[i].band_name_ == band->name_)
{ {
return stations_[i].offset_; return stations_[i].offset_;
} }
} }
} }
return 0; // no offset
return 0; // no offset
} }
int StationList::impl::rowCount (QModelIndex const& parent) const int StationList::impl::rowCount (QModelIndex const& parent) const
@ -260,7 +238,7 @@ Qt::ItemFlags StationList::impl::flags (QModelIndex const& index) const
&& row < stations_.size () && row < stations_.size ()
&& column < num_columns) && column < num_columns)
{ {
if (2 == column) if (description_column == column)
{ {
result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
} }
@ -289,7 +267,7 @@ QVariant StationList::impl::data (QModelIndex const& index, int role) const
{ {
switch (column) switch (column)
{ {
case 0: // band name case band_column:
switch (role) switch (role)
{ {
case SortRole: case SortRole:
@ -318,19 +296,19 @@ QVariant StationList::impl::data (QModelIndex const& index, int role) const
} }
break; break;
case 1: // frequency offset case offset_column:
{ {
auto frequency_offset = stations_.at (row).offset_; auto frequency_offset = stations_.at (row).offset_;
switch (role) switch (role)
{ {
case SortRole:
case Qt::EditRole:
case Qt::AccessibleTextRole: case Qt::AccessibleTextRole:
item = frequency_offset; item = frequency_offset;
break; break;
case SortRole:
case Qt::DisplayRole: case Qt::DisplayRole:
case Qt::EditRole: item = Radio::pretty_frequency_MHz_string (frequency_offset) + " MHz";
item = frequency_offset;
break; break;
case Qt::ToolTipRole: case Qt::ToolTipRole:
@ -345,7 +323,7 @@ QVariant StationList::impl::data (QModelIndex const& index, int role) const
} }
break; break;
case 2: // antenna description case description_column:
switch (role) switch (role)
{ {
case SortRole: case SortRole:
@ -379,9 +357,9 @@ QVariant StationList::impl::headerData (int section, Qt::Orientation orientation
{ {
switch (section) switch (section)
{ {
case 0: header = tr ("Band"); break; case band_column: header = tr ("Band"); break;
case 1: header = tr ("Offset"); break; case offset_column: header = tr ("Offset"); break;
case 2: header = tr ("Antenna Description"); break; case description_column: header = tr ("Antenna Description"); break;
} }
} }
else else
@ -407,7 +385,7 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const&
switch (model_index.column ()) switch (model_index.column ())
{ {
case 0: case band_column:
{ {
// Check if band name is valid. // Check if band name is valid.
auto band_index = first_matching_band (value.toString ()); auto band_index = first_matching_band (value.toString ());
@ -420,7 +398,7 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const&
} }
break; break;
case 1: case offset_column:
{ {
stations_[row].offset_ = value.value<FrequencyDelta> (); stations_[row].offset_ = value.value<FrequencyDelta> ();
Q_EMIT dataChanged (model_index, model_index, roles); Q_EMIT dataChanged (model_index, model_index, roles);
@ -428,7 +406,7 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const&
} }
break; break;
case 2: case description_column:
stations_[row].antenna_description_ = value.toString (); stations_[row].antenna_description_ = value.toString ();
Q_EMIT dataChanged (model_index, model_index, roles); Q_EMIT dataChanged (model_index, model_index, roles);
changed = true; changed = true;
@ -508,9 +486,8 @@ bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction act
{ {
return true; return true;
} }
if (parent.isValid () if (parent.isValid ()
&& 2 == parent.column () && description_column == parent.column ()
&& data->hasFormat (mime_type)) && data->hasFormat (mime_type))
{ {
QByteArray encoded_data {data->data (mime_type)}; QByteArray encoded_data {data->data (mime_type)};
@ -534,17 +511,16 @@ bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction act
QString frequency_string; QString frequency_string;
stream >> frequency_string; stream >> frequency_string;
auto frequency = Radio::frequency (frequency_string, 0); auto frequency = Radio::frequency (frequency_string, 0);
auto band_index = bands_->find (frequency); auto const& band = bands_->find (frequency);
if (stations_.cend () == std::find_if (stations_.cbegin () if (stations_.cend () == std::find_if (stations_.cbegin ()
, stations_.cend () , stations_.cend ()
, [&band_index] (Station const& s) {return s.band_name_ == band_index.data ().toString ();})) , [&band] (Station const& s) {return s.band_name_ == band->name_;}))
{ {
add (Station {band_index.data ().toString (), 0, QString {}}); // not found so add it
add (Station {band->name_, 0, QString {}});
} }
} }
return true; return true;
} }
return false; return false;
} }

View File

@ -59,13 +59,15 @@ public:
using Stations = QList<Station>; using Stations = QList<Station>;
enum Column {band_column, offset_column, description_column};
explicit StationList (Bands const * bands, QObject * parent = nullptr); explicit StationList (Bands const * bands, QObject * parent = nullptr);
explicit StationList (Bands const * bands, Stations, QObject * parent = nullptr); explicit StationList (Bands const * bands, Stations, QObject * parent = nullptr);
~StationList (); ~StationList ();
// Load and store contents. // Load and query contents.
StationList& operator = (Stations); Stations station_list (Stations);
Stations stations () const; Stations const& station_list () const;
// //
// Model API // Model API
@ -83,10 +85,6 @@ private:
pimpl<impl> m_; pimpl<impl> m_;
}; };
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug debug, StationList::Station const&);
#endif
// Station equivalence // Station equivalence
inline inline
bool operator == (StationList::Station const& lhs, StationList::Station const& rhs) bool operator == (StationList::Station const& lhs, StationList::Station const& rhs)
@ -96,6 +94,13 @@ bool operator == (StationList::Station const& lhs, StationList::Station const& r
&& lhs.antenna_description_ == rhs.antenna_description_; && lhs.antenna_description_ == rhs.antenna_description_;
} }
QDataStream& operator << (QDataStream&, StationList::Station const&);
QDataStream& operator >> (QDataStream&, StationList::Station&);
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug debug, StationList::Station const&);
#endif
Q_DECLARE_METATYPE (StationList::Station); Q_DECLARE_METATYPE (StationList::Station);
Q_DECLARE_METATYPE (StationList::Stations); Q_DECLARE_METATYPE (StationList::Stations);

View File

@ -2,18 +2,6 @@
#include "moc_Transceiver.cpp" #include "moc_Transceiver.cpp"
namespace
{
struct init
{
init ()
{
qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState");
qRegisterMetaType<Transceiver::MODE> ("Transceiver::MODE");
}
} static_initialization;
}
#if !defined (QT_NO_DEBUG_STREAM) #if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Transceiver, MODE); ENUM_QDEBUG_OPS_IMPL (Transceiver, MODE);

View File

@ -21,25 +21,6 @@ char const * const TransceiverFactory::basic_transceiver_name_ = "None";
namespace namespace
{ {
struct init
{
init ()
{
qRegisterMetaType<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits");
qRegisterMetaType<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaType<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
qRegisterMetaType<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod");
qRegisterMetaTypeStreamOperators<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod");
qRegisterMetaType<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource");
qRegisterMetaTypeStreamOperators<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource");
qRegisterMetaType<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode");
qRegisterMetaTypeStreamOperators<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode");
}
} static_initializer;
enum // supported non-hamlib radio interfaces enum // supported non-hamlib radio interfaces
{ {
NonHamlibBaseId = 9899 NonHamlibBaseId = 9899

View File

@ -33,14 +33,6 @@ namespace
{ {
int constexpr points {256}; int constexpr points {256};
struct init
{
init ()
{
qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours");
}
} static_initaializer;
using Colours = WFPalette::Colours; using Colours = WFPalette::Colours;
// ensure that palette colours are useable for interpolation // ensure that palette colours are useable for interpolation

View File

@ -23,7 +23,7 @@
#endif #endif
#include "revision_utils.hpp" #include "revision_utils.hpp"
#include "MetaDataRegistry.hpp"
#include "SettingsGroup.hpp" #include "SettingsGroup.hpp"
#include "TraceFile.hpp" #include "TraceFile.hpp"
#include "mainwindow.h" #include "mainwindow.h"
@ -31,6 +31,8 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
register_types (); // make the Qt magic happen
// Multiple instances: // Multiple instances:
QSharedMemory mem_jt9; QSharedMemory mem_jt9;

View File

@ -61,27 +61,6 @@ namespace
} }
} }
class BandAndFrequencyItemDelegate final
: public QStyledItemDelegate
{
public:
explicit BandAndFrequencyItemDelegate (Bands const * bands, QObject * parent = nullptr)
: QStyledItemDelegate {parent}
, bands_ {bands}
{
}
QString displayText (QVariant const& v, QLocale const&) const override
{
return Radio::pretty_frequency_MHz_string (Radio::frequency (v, 6))
+ QChar::Nbsp
+ '(' + (bands_->data (bands_->find (Radio::frequency (v, 6)))).toString () + ')';
}
private:
Bands const * bands_;
};
//--------------------------------------------------- MainWindow constructor //--------------------------------------------------- MainWindow constructor
MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdmem, MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdmem,
unsigned downSampleFactor, QWidget *parent) : unsigned downSampleFactor, QWidget *parent) :
@ -278,15 +257,11 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
// Hook up working frequencies. // Hook up working frequencies.
ui->bandComboBox->setModel (m_config.frequencies ()); ui->bandComboBox->setModel (m_config.frequencies ());
ui->bandComboBox->setModelColumn (1); // MHz ui->bandComboBox->setModelColumn (FrequencyList::frequency_mhz_column);
// Add delegate to show bands alongside frequencies in combo box // combo box drop down width defaults to the line edit + decorator width,
// popup list. // here we change that to the column width size hint of the model column
ui->bandComboBox->view ()->setItemDelegateForColumn (1, new BandAndFrequencyItemDelegate {m_config.bands (), this}); ui->bandComboBox->view ()->setMinimumWidth (ui->bandComboBox->view ()->sizeHintForColumn (FrequencyList::frequency_mhz_column));
// combo box drop downs are limited to the drop down selector width,
// this almost random increase improves the situation
ui->bandComboBox->view ()->setMinimumWidth (ui->bandComboBox->view ()->sizeHintForColumn (1) + 40);
// Enable live band combo box entry validation and action. // Enable live band combo box entry validation and action.
auto band_validator = new LiveFrequencyValidator {ui->bandComboBox auto band_validator = new LiveFrequencyValidator {ui->bandComboBox
@ -646,7 +621,6 @@ void MainWindow::writeSettings()
m_settings->setValue("GUItab",ui->tabWidget->currentIndex()); m_settings->setValue("GUItab",ui->tabWidget->currentIndex());
m_settings->setValue("OutBufSize",outBufSize); m_settings->setValue("OutBufSize",outBufSize);
m_settings->setValue("LockTxFreq",m_lockTxFreq); m_settings->setValue("LockTxFreq",m_lockTxFreq);
m_settings->setValue("Plus2kHz",m_plus2kHz);
m_settings->setValue("PctTx",m_pctx); m_settings->setValue("PctTx",m_pctx);
m_settings->setValue("dBm",m_dBm); m_settings->setValue("dBm",m_dBm);
m_settings->setValue("UploadSpots",m_uploadSpots); m_settings->setValue("UploadSpots",m_uploadSpots);
@ -736,8 +710,6 @@ void MainWindow::readSettings()
outBufSize=m_settings->value("OutBufSize",4096).toInt(); outBufSize=m_settings->value("OutBufSize",4096).toInt();
m_lockTxFreq=m_settings->value("LockTxFreq",false).toBool(); m_lockTxFreq=m_settings->value("LockTxFreq",false).toBool();
ui->cbTxLock->setChecked(m_lockTxFreq); ui->cbTxLock->setChecked(m_lockTxFreq);
m_plus2kHz=m_settings->value("Plus2kHz",false).toBool();
ui->cbPlus2kHz->setChecked(m_plus2kHz);
ui->sunriseBands->setText(m_settings->value("SunriseBands","").toString()); ui->sunriseBands->setText(m_settings->value("SunriseBands","").toString());
on_sunriseBands_editingFinished(); on_sunriseBands_editingFinished();
ui->dayBands->setText(m_settings->value("DayBands","").toString()); ui->dayBands->setText(m_settings->value("DayBands","").toString());
@ -1176,29 +1148,33 @@ void MainWindow::qsy (Frequency f)
void MainWindow::displayDialFrequency () void MainWindow::displayDialFrequency ()
{ {
// lookup band // lookup band
auto bands_model = m_config.bands (); auto const& band_name = m_config.bands ()->find (m_dialFreq)->name_;
QString t {bands_model->data(bands_model->find(m_dialFreq)).toString()}; ui->bandComboBox->setCurrentText (band_name);
ui->bandComboBox->setCurrentText (t); m_wideGraph->setRxBand (band_name);
m_wideGraph->setRxBand(t);
// search working frequencies for one we are within 10kHz of // search working frequencies for one we are within 10kHz of (1 Mhz
auto frequencies = m_config.frequencies (); // of on VHF and up)
bool valid {false}; bool valid {false};
quint64 min_offset=99999999; quint64 min_offset {99999999};
auto const& frequencies = m_config.frequencies ();
for (int row = 0; row < frequencies->rowCount (); ++row) { for (int row = 0; row < frequencies->rowCount (); ++row)
{
auto const& source_row = frequencies->mapToSource (frequencies->index (row, 0)).row ();
auto const& item = frequencies->frequency_list ()[source_row];
// we need to do specific checks for above and below here to // we need to do specific checks for above and below here to
// ensure that we can use unsigned Radio::Frequency since we // ensure that we can use unsigned Radio::Frequency since we
// potentially use the full 64-bit unsigned range. // potentially use the full 64-bit unsigned range.
auto working_frequency = frequencies->data (frequencies->index (row, 0)).value<Frequency> (); auto const& working_frequency = item.frequency_;
auto offset = m_dialFreq > working_frequency ? m_dialFreq - working_frequency : working_frequency - m_dialFreq; auto const& offset = m_dialFreq > working_frequency ? m_dialFreq - working_frequency : working_frequency - m_dialFreq;
if(offset<min_offset) { if (offset < min_offset) {
m_freqNominal=working_frequency; m_freqNominal = working_frequency;
min_offset=offset; min_offset = offset;
} }
} }
if ((min_offset < 10000u) or (m_config.enable_VHF_features() and if (min_offset < 10000u or (m_config.enable_VHF_features() and
min_offset < 1000000u)) valid = true; min_offset < 1000000u)) {
valid = true;
}
ui->labDialFreq->setProperty ("oob", !valid); ui->labDialFreq->setProperty ("oob", !valid);
// the following sequence is necessary to update the style // the following sequence is necessary to update the style
@ -1672,15 +1648,16 @@ void MainWindow::readFromStdout() //readFromStdout
msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ()); msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ());
} }
if (m_config.insert_blank () && m_blankLine) { if (m_config.insert_blank () && m_blankLine)
QString band; {
if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50) { QString band;
auto const& bands_model = m_config.bands (); if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50)
band = ' ' + bands_model->data (bands_model->find (m_dialFreq + ui->TxFreqSpinBox->value ())).toString (); {
} band = ' ' + QString {m_config.bands ()->find (m_dialFreq)->name_};
ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-')); }
m_blankLine = false; ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-'));
} m_blankLine = false;
}
DecodedText decodedtext; DecodedText decodedtext;
decodedtext = t.replace("\n",""); //t.replace("\n","").mid(0,t.length()-4); decodedtext = t.replace("\n",""); //t.replace("\n","").mid(0,t.length()-4);
@ -2251,9 +2228,8 @@ void MainWindow::startTx2()
transmit (snr); transmit (snr);
signalMeter->setValue(0); signalMeter->setValue(0);
if(m_mode.mid(0,4)=="WSPR" and !m_tune) { if(m_mode.mid(0,4)=="WSPR" and !m_tune) {
auto const& bands_model = m_config.bands ();
t = " Transmiting " + m_mode + " ----------------------- " + t = " Transmiting " + m_mode + " ----------------------- " +
bands_model->data(bands_model->find(m_dialFreq)).toString (); m_config.bands ()->find (m_dialFreq)->name_;
ui->decodedTextBrowser->append(t.rightJustified (71, '-')); ui->decodedTextBrowser->append(t.rightJustified (71, '-'));
QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")}; QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")};
@ -2986,10 +2962,8 @@ void MainWindow::acceptQSO2(QDateTime const& QSO_date, QString const& call, QStr
, QString const& tx_power, QString const& comments , QString const& tx_power, QString const& comments
, QString const& name) , QString const& name)
{ {
auto const& bands_model = m_config.bands ();
auto band = bands_model->data (bands_model->find (m_dialFreq + ui->TxFreqSpinBox->value ())).toString ();
QString date = m_dateTimeQSO.toString("yyyyMMdd"); QString date = m_dateTimeQSO.toString("yyyyMMdd");
m_logBook.addAsWorked(m_hisCall,band,m_modeTx,date); m_logBook.addAsWorked (m_hisCall, m_config.bands ()->find (m_dialFreq)->name_, m_modeTx, date);
m_messageClient->qso_logged (QSO_date, call, grid, dial_freq, mode, rpt_sent, rpt_received, tx_power, comments, name); m_messageClient->qso_logged (QSO_date, call, grid, dial_freq, mode, rpt_sent, rpt_received, tx_power, comments, name);
@ -3009,6 +2983,7 @@ void MainWindow::acceptQSO2(QDateTime const& QSO_date, QString const& call, QStr
void MainWindow::on_actionJT9_1_triggered() void MainWindow::on_actionJT9_1_triggered()
{ {
m_mode="JT9"; m_mode="JT9";
switch_mode (Modes::JT9);
if(m_modeTx!="JT9") on_pbTxMode_clicked(); if(m_modeTx!="JT9") on_pbTxMode_clicked();
statusChanged(); statusChanged();
m_TRperiod=60; m_TRperiod=60;
@ -3036,6 +3011,7 @@ void MainWindow::on_actionJT9_1_triggered()
void MainWindow::on_actionJT9W_1_triggered() void MainWindow::on_actionJT9W_1_triggered()
{ {
m_mode="JT9W-1"; m_mode="JT9W-1";
switch_mode (Modes::JT9W_1);
if(m_modeTx!="JT9") on_pbTxMode_clicked(); if(m_modeTx!="JT9") on_pbTxMode_clicked();
statusChanged(); statusChanged();
m_TRperiod=60; m_TRperiod=60;
@ -3068,6 +3044,7 @@ void MainWindow::on_actionJT65_triggered()
on_pbTxMode_clicked(); on_pbTxMode_clicked();
} }
m_mode="JT65"; m_mode="JT65";
switch_mode (Modes::JT65);
if(m_modeTx!="JT65") on_pbTxMode_clicked(); if(m_modeTx!="JT65") on_pbTxMode_clicked();
statusChanged(); statusChanged();
m_TRperiod=60; m_TRperiod=60;
@ -3105,6 +3082,7 @@ void MainWindow::on_actionJT65_triggered()
void MainWindow::on_actionJT9_JT65_triggered() void MainWindow::on_actionJT9_JT65_triggered()
{ {
m_mode="JT9+JT65"; m_mode="JT9+JT65";
switch_mode (Modes::JT65);
if(m_modeTx != "JT65") m_modeTx="JT9"; if(m_modeTx != "JT65") m_modeTx="JT9";
m_nSubMode=0; //Dual-mode always means JT9 and JT65A m_nSubMode=0; //Dual-mode always means JT9 and JT65A
statusChanged(); statusChanged();
@ -3133,6 +3111,7 @@ void MainWindow::on_actionJT9_JT65_triggered()
void MainWindow::on_actionJT4_triggered() void MainWindow::on_actionJT4_triggered()
{ {
m_mode="JT4"; m_mode="JT4";
switch_mode (Modes::JT4);
m_modeTx="JT4"; m_modeTx="JT4";
statusChanged(); statusChanged();
m_TRperiod=60; m_TRperiod=60;
@ -3171,6 +3150,7 @@ void MainWindow::on_actionJT4_triggered()
void MainWindow::on_actionWSPR_2_triggered() void MainWindow::on_actionWSPR_2_triggered()
{ {
m_mode="WSPR-2"; m_mode="WSPR-2";
switch_mode (Modes::WSPR);
m_modeTx="WSPR-2"; //### not needed ?? ### m_modeTx="WSPR-2"; //### not needed ?? ###
statusChanged(); statusChanged();
m_TRperiod=120; m_TRperiod=120;
@ -3194,8 +3174,20 @@ void MainWindow::on_actionWSPR_2_triggered()
void MainWindow::on_actionWSPR_15_triggered() void MainWindow::on_actionWSPR_15_triggered()
{ {
msgBox("WSPR-15 is not yet available"); msgBox("WSPR-15 is not yet available");
switch_mode (Modes::WSPR);
} }
void MainWindow::switch_mode (Mode mode)
{
auto f = m_dialFreq;
m_config.frequencies ()->filter (mode);
auto const& index = m_config.frequencies ()->best_working_frequency (f, mode);
if (index.isValid ())
{
ui->bandComboBox->setCurrentIndex (index.row ());
on_bandComboBox_activated (index.row ());
}
}
void MainWindow::WSPR_config(bool b) void MainWindow::WSPR_config(bool b)
{ {
@ -3328,26 +3320,44 @@ bool MainWindow::gridOK(QString g)
return b; return b;
} }
void MainWindow::on_bandComboBox_currentIndexChanged (int index)
{
auto const& frequencies = m_config.frequencies ();
auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList::frequency_column));
Frequency frequency {m_dialFreq};
if (source_index.isValid ())
{
frequency = frequencies->frequency_list ()[source_index.row ()].frequency_;
}
// Lookup band
auto const& band = m_config.bands ()->find (frequency);
auto const& out_of_band = m_config.bands ()->out_of_band ();
if (out_of_band != band)
{
ui->bandComboBox->lineEdit ()->setStyleSheet ({});
ui->bandComboBox->setCurrentText (band->name_);
}
else
{
ui->bandComboBox->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}");
ui->bandComboBox->setCurrentText (out_of_band->name_);
}
displayDialFrequency ();
}
void MainWindow::on_bandComboBox_activated (int index) void MainWindow::on_bandComboBox_activated (int index)
{ {
auto frequencies = m_config.frequencies (); auto const& frequencies = m_config.frequencies ();
auto frequency = frequencies->data (frequencies->index (index, 0)); auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList::frequency_column));
// Lookup band Frequency frequency {m_dialFreq};
auto bands = m_config.bands (); if (source_index.isValid ())
auto band_index = bands->find (frequency); {
if (band_index.isValid ()) { frequency = frequencies->frequency_list ()[source_index.row ()].frequency_;
ui->bandComboBox->lineEdit ()->setStyleSheet ({}); }
ui->bandComboBox->setCurrentText (band_index.data ().toString ());
} else {
ui->bandComboBox->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}");
ui->bandComboBox->setCurrentText (bands->data (QModelIndex {}).toString ());
}
auto f = frequency.value<Frequency> ();
if (m_plus2kHz) f += 2000;
m_bandEdited = true; m_bandEdited = true;
band_changed (f); band_changed (frequency);
m_wideGraph->setRxBand(band_index.data().toString()); m_wideGraph->setRxBand (m_config.bands ()->find (frequency)->name_);
// qDebug() << "bandComboBox_activated" << index << 0.000001*f;
} }
void MainWindow::band_changed (Frequency f) void MainWindow::band_changed (Frequency f)
@ -3607,23 +3617,6 @@ void MainWindow::on_cbTxLock_clicked(bool checked)
if(m_lockTxFreq) on_pbR2T_clicked(); if(m_lockTxFreq) on_pbR2T_clicked();
} }
void MainWindow::on_cbPlus2kHz_toggled(bool checked)
{
m_plus2kHz = checked;
if (m_config.transceiver_online (false)) { // update state only if not starting up
psk_Reporter->sendReport(); // Upload any queued spots before changing band
auto f = m_dialFreq;
if (m_plus2kHz) {
f += 2000;
} else {
f -= 2000;
}
m_bandEdited = true;
band_changed (f);
}
}
void MainWindow::handle_transceiver_update (Transceiver::TransceiverState s) void MainWindow::handle_transceiver_update (Transceiver::TransceiverState s)
{ {
transmitDisplay (s.ptt ()); transmitDisplay (s.ptt ());
@ -3868,9 +3861,6 @@ void MainWindow::transmitDisplay (bool transmitting)
ui->cbTxLock->setEnabled (QSY_allowed); ui->cbTxLock->setEnabled (QSY_allowed);
} }
// Allow +2kHz only when not transmitting or if TX QSYs are allowed
ui->cbPlus2kHz->setEnabled (!transmitting || m_config.tx_QSY_allowed ());
// the following are always disallowed in transmit // the following are always disallowed in transmit
ui->menuMode->setEnabled (!transmitting); ui->menuMode->setEnabled (!transmitting);
ui->bandComboBox->setEnabled (!transmitting); ui->bandComboBox->setEnabled (!transmitting);
@ -4173,9 +4163,8 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
if (m_config.insert_blank () && m_blankLine) { if (m_config.insert_blank () && m_blankLine) {
QString band; QString band;
auto const& bands_model = m_config.bands ();
Frequency f=1000000.0*rxFields.at(3).toDouble()+0.5; Frequency f=1000000.0*rxFields.at(3).toDouble()+0.5;
band = ' ' + bands_model->data (bands_model->find (f)).toString (); band = ' ' + m_config.bands ()->find (f)->name_;
ui->decodedTextBrowser->append(band.rightJustified (71, '-')); ui->decodedTextBrowser->append(band.rightJustified (71, '-'));
m_blankLine = false; m_blankLine = false;
} }
@ -4355,10 +4344,9 @@ void MainWindow::bandHopping()
m_band00=iband; m_band00=iband;
auto frequencies = m_config.frequencies (); auto frequencies = m_config.frequencies ();
for (int i=0; i<99; i++) { for (int row = 0; row < frequencies->rowCount (); ++row) {
auto frequency=frequencies->data (frequencies->index (i, 0)); auto frequency=frequencies->data (frequencies->index (row, FrequencyList::frequency_column));
auto f = frequency.value<Frequency>(); auto f = frequency.value<Frequency>();
if(f==0) break;
if(f==f0) { if(f==f0) {
on_bandComboBox_activated(i); //Set new band on_bandComboBox_activated(i); //Set new band
// qDebug() << nhr << nmin << int(sec) << "Band selected" << i << 0.000001*f0 << 0.000001*f; // qDebug() << nhr << nmin << int(sec) << "Band selected" << i << 0.000001*f0 << 0.000001*f;

View File

@ -22,6 +22,7 @@
#include "soundout.h" #include "soundout.h"
#include "commons.h" #include "commons.h"
#include "Radio.hpp" #include "Radio.hpp"
#include "Modes.hpp"
#include "Configuration.hpp" #include "Configuration.hpp"
#include "Transceiver.hpp" #include "Transceiver.hpp"
#include "psk_reporter.h" #include "psk_reporter.h"
@ -65,6 +66,7 @@ class MainWindow : public QMainWindow
public: public:
using Frequency = Radio::Frequency; using Frequency = Radio::Frequency;
using Mode = Modes::Mode;
// Multiple instances: call MainWindow() with *thekey // Multiple instances: call MainWindow() with *thekey
explicit MainWindow(bool multiple, QSettings *, QSharedMemory *shdmem, explicit MainWindow(bool multiple, QSettings *, QSharedMemory *shdmem,
@ -176,12 +178,12 @@ private slots:
, QString const& rpt_sent, QString const& rpt_received , QString const& rpt_sent, QString const& rpt_received
, QString const& tx_power, QString const& comments , QString const& tx_power, QString const& comments
, QString const& name); , QString const& name);
void on_bandComboBox_currentIndexChanged (int index);
void on_bandComboBox_activated (int index); void on_bandComboBox_activated (int index);
void on_readFreq_clicked(); void on_readFreq_clicked();
void on_pbTxMode_clicked(); void on_pbTxMode_clicked();
void on_RxFreqSpinBox_valueChanged(int n); void on_RxFreqSpinBox_valueChanged(int n);
void on_cbTxLock_clicked(bool checked); void on_cbTxLock_clicked(bool checked);
void on_cbPlus2kHz_toggled(bool checked);
void on_outAttenuation_valueChanged (int); void on_outAttenuation_valueChanged (int);
void rigOpen (); void rigOpen ();
void handle_transceiver_update (Transceiver::TransceiverState); void handle_transceiver_update (Transceiver::TransceiverState);
@ -233,8 +235,6 @@ private slots:
void on_graylineDuration_editingFinished(); void on_graylineDuration_editingFinished();
private: private:
void enable_DXCC_entity (bool on);
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo, Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
unsigned channels, unsigned msBuffered) const; unsigned channels, unsigned msBuffered) const;
Q_SIGNAL void stopAudioOutputStream () const; Q_SIGNAL void stopAudioOutputStream () const;
@ -370,7 +370,6 @@ private:
bool m_lockTxFreq; bool m_lockTxFreq;
bool m_tx2QSO; bool m_tx2QSO;
bool m_CATerror; bool m_CATerror;
bool m_plus2kHz;
bool m_bAstroData; bool m_bAstroData;
bool m_bEME; bool m_bEME;
bool m_bShMsgs; bool m_bShMsgs;
@ -507,6 +506,8 @@ private:
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text); void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text);
void replayDecodes (); void replayDecodes ();
void postDecode (bool is_new, QString const& message); void postDecode (bool is_new, QString const& message);
void enable_DXCC_entity (bool on);
void switch_mode (Mode);
void bandHopping(); void bandHopping();
}; };

View File

@ -1348,16 +1348,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="cbPlus2kHz">
<property name="toolTip">
<string>Add 2 kHz to requested dial frequency</string>
</property>
<property name="text">
<string>+2 kHz</string>
</property>
</widget>
</item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QPushButton" name="readFreq"> <widget class="QPushButton" name="readFreq">
<property name="maximumSize"> <property name="maximumSize">