mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-23 12:48:40 -05:00
Ensure all model proxy caches are flushed before access
This fixes a defect where station detail changes are not saved. The Qt sort and filter proxy models utilize an item cache that must be flushed by callig submit() before accessing the underlying model if the proxy model has been used for updates. Also separated the item model candidate key filter from the implementation internals of the foreign key item delegate so that candidate key filtered models can be used directly as view models. Make the insert new station details band combo box use a candidate key filtered item model to avoid constraint violations. Constraint is zero or one station records per band. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5161 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
fdc02e34d4
commit
dad4863e84
@ -184,6 +184,7 @@ set (wsjt_qt_CXXSRCS
|
|||||||
StationList.cpp
|
StationList.cpp
|
||||||
FrequencyLineEdit.cpp
|
FrequencyLineEdit.cpp
|
||||||
FrequencyItemDelegate.cpp
|
FrequencyItemDelegate.cpp
|
||||||
|
CandidateKeyFilter.cpp
|
||||||
ForeignKeyDelegate.cpp
|
ForeignKeyDelegate.cpp
|
||||||
LiveFrequencyValidator.cpp
|
LiveFrequencyValidator.cpp
|
||||||
GetUserId.cpp
|
GetUserId.cpp
|
||||||
|
70
CandidateKeyFilter.cpp
Normal file
70
CandidateKeyFilter.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "CandidateKeyFilter.hpp"
|
||||||
|
|
||||||
|
#include <QModelIndex>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
#include "pimpl_impl.hpp"
|
||||||
|
|
||||||
|
class CandidateKeyFilter::impl final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit impl (QAbstractItemModel const * referencing_model
|
||||||
|
, int referencing_key_column
|
||||||
|
, int referenced_key_column
|
||||||
|
, int referencing_key_role
|
||||||
|
, int referenced_key_role)
|
||||||
|
: referencing_ {referencing_model}
|
||||||
|
, referencing_key_column_ {referencing_key_column}
|
||||||
|
, referencing_key_role_ {referencing_key_role}
|
||||||
|
, referenced_key_column_ {referenced_key_column}
|
||||||
|
, referenced_key_role_ {referenced_key_role}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractItemModel const * referencing_;
|
||||||
|
int referencing_key_column_;
|
||||||
|
int referencing_key_role_;
|
||||||
|
int referenced_key_column_;
|
||||||
|
int referenced_key_role_;
|
||||||
|
QModelIndex active_key_;
|
||||||
|
};
|
||||||
|
|
||||||
|
CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel const * referencing_model
|
||||||
|
, QAbstractItemModel * referenced_model
|
||||||
|
, int referencing_key_column
|
||||||
|
, int referenced_key_column
|
||||||
|
, int referencing_key_role
|
||||||
|
, int referenced_key_role)
|
||||||
|
: QSortFilterProxyModel {nullptr} // ForeignKeyDelegate owns us
|
||||||
|
, m_ {referencing_model, referencing_key_column, referenced_key_column, referencing_key_role, referenced_key_role}
|
||||||
|
{
|
||||||
|
setSourceModel (referenced_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
CandidateKeyFilter::~CandidateKeyFilter ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CandidateKeyFilter::set_active_key (QModelIndex const& index)
|
||||||
|
{
|
||||||
|
if (index.isValid () )
|
||||||
|
{
|
||||||
|
Q_ASSERT (index.column () == m_->referencing_key_column_);
|
||||||
|
m_->active_key_ = index;
|
||||||
|
}
|
||||||
|
invalidateFilter ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CandidateKeyFilter::filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const
|
||||||
|
{
|
||||||
|
auto candidate_key = sourceModel ()->index (candidate_row, m_->referenced_key_column_, candidate_parent).data (m_->referenced_key_role_);
|
||||||
|
|
||||||
|
// Include the current key.
|
||||||
|
if (m_->active_key_.isValid () && candidate_key == m_->active_key_.data (m_->referencing_key_role_))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out any candidates already in the referencing key rows.
|
||||||
|
return m_->referencing_->match (m_->referencing_->index (0, m_->referencing_key_column_), m_->referencing_key_role_, candidate_key, 1, Qt::MatchExactly).isEmpty ();
|
||||||
|
}
|
36
CandidateKeyFilter.hpp
Normal file
36
CandidateKeyFilter.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef CANDIDATE_KEY_FILTER_HPP_
|
||||||
|
#define CANDIDATE_KEY_FILTER_HPP_
|
||||||
|
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QModelIndex>
|
||||||
|
|
||||||
|
#include "pimpl_h.hpp"
|
||||||
|
|
||||||
|
class QAbstractItemModel;
|
||||||
|
|
||||||
|
class CandidateKeyFilter final
|
||||||
|
: public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CandidateKeyFilter (QAbstractItemModel const * referencing_model
|
||||||
|
, QAbstractItemModel * referenced_model
|
||||||
|
, int referencing_key_column = 0
|
||||||
|
, int referenced_key_column = 0
|
||||||
|
, int referencing_key_role = Qt::EditRole
|
||||||
|
, int referenced_key_role = Qt::EditRole);
|
||||||
|
~CandidateKeyFilter ();
|
||||||
|
|
||||||
|
// this key is not to be filtered, usually because we want to allow
|
||||||
|
// it since we are editing the row that contains it this it is valid
|
||||||
|
// even though it is in use
|
||||||
|
void set_active_key (QModelIndex const& index = QModelIndex {});
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class impl;
|
||||||
|
pimpl<impl> m_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -155,12 +155,14 @@
|
|||||||
#include <QFontDialog>
|
#include <QFontDialog>
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
#include <QSerialPortInfo>
|
#include <QSerialPortInfo>
|
||||||
|
#include <QScopedPointer>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "qt_helpers.hpp"
|
#include "qt_helpers.hpp"
|
||||||
#include "SettingsGroup.hpp"
|
#include "SettingsGroup.hpp"
|
||||||
#include "FrequencyLineEdit.hpp"
|
#include "FrequencyLineEdit.hpp"
|
||||||
#include "FrequencyItemDelegate.hpp"
|
#include "FrequencyItemDelegate.hpp"
|
||||||
|
#include "CandidateKeyFilter.hpp"
|
||||||
#include "ForeignKeyDelegate.hpp"
|
#include "ForeignKeyDelegate.hpp"
|
||||||
#include "TransceiverFactory.hpp"
|
#include "TransceiverFactory.hpp"
|
||||||
#include "Transceiver.hpp"
|
#include "Transceiver.hpp"
|
||||||
@ -240,13 +242,13 @@ class StationDialog final
|
|||||||
: public QDialog
|
: public QDialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit StationDialog (Bands * bands, QWidget * parent = nullptr)
|
explicit StationDialog (StationList const * stations, Bands * bands, QWidget * parent = nullptr)
|
||||||
: QDialog {parent}
|
: QDialog {parent}
|
||||||
, bands_ {bands}
|
, filtered_bands_ {new CandidateKeyFilter {stations, bands}}
|
||||||
{
|
{
|
||||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Station"));
|
setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Station"));
|
||||||
|
|
||||||
band_.setModel (bands_);
|
band_.setModel (filtered_bands_.data ());
|
||||||
|
|
||||||
auto form_layout = new QFormLayout ();
|
auto form_layout = new QFormLayout ();
|
||||||
form_layout->addRow (tr ("&Band:"), &band_);
|
form_layout->addRow (tr ("&Band:"), &band_);
|
||||||
@ -273,8 +275,14 @@ public:
|
|||||||
return {band_.currentText (), delta_.frequency_delta (), description_.text ()};
|
return {band_.currentText (), delta_.frequency_delta (), description_.text ()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int exec () override
|
||||||
|
{
|
||||||
|
filtered_bands_->set_active_key ();
|
||||||
|
return QDialog::exec ();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Bands * bands_;
|
QScopedPointer<CandidateKeyFilter> filtered_bands_;
|
||||||
|
|
||||||
QComboBox band_;
|
QComboBox band_;
|
||||||
FrequencyDeltaLineEdit delta_;
|
FrequencyDeltaLineEdit delta_;
|
||||||
@ -724,7 +732,7 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
|
|||||||
, stations_ {&bands_}
|
, stations_ {&bands_}
|
||||||
, next_stations_ {&bands_}
|
, next_stations_ {&bands_}
|
||||||
, frequency_dialog_ {new FrequencyDialog {this}}
|
, frequency_dialog_ {new FrequencyDialog {this}}
|
||||||
, station_dialog_ {new StationDialog {&bands_, this}}
|
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
|
||||||
, rig_active_ {false}
|
, rig_active_ {false}
|
||||||
, have_rig_ {false}
|
, have_rig_ {false}
|
||||||
, rig_changed_ {false}
|
, rig_changed_ {false}
|
||||||
@ -922,7 +930,7 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
|
|||||||
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 (0, Qt::AscendingOrder);
|
||||||
ui_->stations_table_view->setColumnWidth (1, 150);
|
ui_->stations_table_view->setColumnWidth (1, 150);
|
||||||
ui_->stations_table_view->setItemDelegateForColumn (0, new ForeignKeyDelegate {&next_stations_, &bands_, 0, this});
|
ui_->stations_table_view->setItemDelegateForColumn (0, new ForeignKeyDelegate {&next_stations_, &bands_, 0, 0, this});
|
||||||
ui_->stations_table_view->setItemDelegateForColumn (1, new FrequencyDeltaItemDelegate {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};
|
||||||
|
@ -1,77 +1,32 @@
|
|||||||
#include "ForeignKeyDelegate.hpp"
|
#include "ForeignKeyDelegate.hpp"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
|
#include "CandidateKeyFilter.hpp"
|
||||||
class CandidateKeyFilter final
|
|
||||||
: public QSortFilterProxyModel
|
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referencing_model
|
||||||
{
|
, QAbstractItemModel * referenced_model
|
||||||
public:
|
, int referencing_key_column
|
||||||
explicit CandidateKeyFilter (QAbstractItemModel const * referencing_model
|
, int referenced_key_column
|
||||||
, QAbstractItemModel * referenced_model
|
, QObject * parent
|
||||||
, int referenced_key_column
|
, int referencing_key_role
|
||||||
, int referencing_key_role
|
, int referenced_key_role)
|
||||||
, int referenced_key_role)
|
: QStyledItemDelegate {parent}
|
||||||
: QSortFilterProxyModel {nullptr} // ForeignKeyDelegate owns us
|
, candidate_key_filter_ {new CandidateKeyFilter {referencing_model, referenced_model, referencing_key_column, referenced_key_column, referencing_key_role, referenced_key_role}}
|
||||||
, referencing_ {referencing_model}
|
{
|
||||||
, referencing_key_role_ {referencing_key_role}
|
}
|
||||||
, referenced_key_column_ {referenced_key_column}
|
|
||||||
, referenced_key_role_ {referenced_key_role}
|
ForeignKeyDelegate::~ForeignKeyDelegate ()
|
||||||
{
|
{
|
||||||
setSourceModel (referenced_model);
|
}
|
||||||
}
|
|
||||||
|
QWidget * ForeignKeyDelegate::createEditor (QWidget * parent
|
||||||
void set_active_key (QModelIndex const& index)
|
, QStyleOptionViewItem const& /* option */
|
||||||
{
|
, QModelIndex const& index) const
|
||||||
active_key_ = index;
|
{
|
||||||
invalidateFilter ();
|
auto editor = new QComboBox {parent};
|
||||||
}
|
editor->setFrame (false);
|
||||||
|
candidate_key_filter_->set_active_key (index);
|
||||||
protected:
|
editor->setModel (candidate_key_filter_.data ());
|
||||||
bool filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const override
|
return editor;
|
||||||
{
|
}
|
||||||
auto candidate_key = sourceModel ()->index (candidate_row, referenced_key_column_, candidate_parent).data (referenced_key_role_);
|
|
||||||
|
|
||||||
// Include the current key.
|
|
||||||
if (candidate_key == active_key_.data (referencing_key_role_))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter out any candidates already in the referencing key rows.
|
|
||||||
return referencing_->match (referencing_->index (0, active_key_.column ()), referencing_key_role_, candidate_key, 1, Qt::MatchExactly).isEmpty ();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QAbstractItemModel const * referencing_;
|
|
||||||
int referencing_key_role_;
|
|
||||||
int referenced_key_column_;
|
|
||||||
int referenced_key_role_;
|
|
||||||
QModelIndex active_key_;
|
|
||||||
};
|
|
||||||
|
|
||||||
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referencing_model
|
|
||||||
, QAbstractItemModel * referenced_model
|
|
||||||
, int referenced_key_column
|
|
||||||
, QObject * parent
|
|
||||||
, int referencing_key_role
|
|
||||||
, int referenced_key_role)
|
|
||||||
: QStyledItemDelegate {parent}
|
|
||||||
, candidate_key_filter_ {new CandidateKeyFilter {referencing_model, referenced_model, referenced_key_column, referencing_key_role, referenced_key_role}}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ForeignKeyDelegate::~ForeignKeyDelegate ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget * ForeignKeyDelegate::createEditor (QWidget * parent
|
|
||||||
, QStyleOptionViewItem const& /* option */
|
|
||||||
, QModelIndex const& index) const
|
|
||||||
{
|
|
||||||
auto editor = new QComboBox {parent};
|
|
||||||
editor->setFrame (false);
|
|
||||||
candidate_key_filter_->set_active_key (index);
|
|
||||||
editor->setModel (candidate_key_filter_.data ());
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
@ -1,34 +1,35 @@
|
|||||||
#ifndef FOREIGN_KEY_DELEGATE_HPP_
|
#ifndef FOREIGN_KEY_DELEGATE_HPP_
|
||||||
#define FOREIGN_KEY_DELEGATE_HPP_
|
#define FOREIGN_KEY_DELEGATE_HPP_
|
||||||
|
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
|
||||||
class CandidateKeyFilter;
|
class CandidateKeyFilter;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Class ForeignKeyDelegate
|
// Class ForeignKeyDelegate
|
||||||
//
|
//
|
||||||
// Item delegate for editing a foreign key item in a one or many
|
// Item delegate for editing a foreign key item in a one or many
|
||||||
// to one relationship. A QComboBox is used as an item delegate
|
// to one relationship. A QComboBox is used as an item delegate
|
||||||
// for the edit role.
|
// for the edit role.
|
||||||
//
|
//
|
||||||
class ForeignKeyDelegate final
|
class ForeignKeyDelegate final
|
||||||
: public QStyledItemDelegate
|
: public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ForeignKeyDelegate (QAbstractItemModel const * referencing_model
|
explicit ForeignKeyDelegate (QAbstractItemModel const * referencing_model
|
||||||
, QAbstractItemModel * referenced_model
|
, QAbstractItemModel * referenced_model
|
||||||
, int referenced_key_column = 0
|
, int referencing_key_column = 0
|
||||||
, QObject * parent = nullptr
|
, int referenced_key_column = 0
|
||||||
, int referencing_key_role = Qt::EditRole
|
, QObject * parent = nullptr
|
||||||
, int referenced_key_role = Qt::EditRole);
|
, int referencing_key_role = Qt::EditRole
|
||||||
~ForeignKeyDelegate ();
|
, int referenced_key_role = Qt::EditRole);
|
||||||
|
~ForeignKeyDelegate ();
|
||||||
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
|
|
||||||
|
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
|
||||||
private:
|
|
||||||
QScopedPointer<CandidateKeyFilter> candidate_key_filter_;
|
private:
|
||||||
};
|
QScopedPointer<CandidateKeyFilter> candidate_key_filter_;
|
||||||
|
};
|
||||||
#endif
|
|
||||||
|
#endif
|
||||||
|
@ -1,358 +1,359 @@
|
|||||||
#include "FrequencyList.hpp"
|
#include "FrequencyList.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QListIterator>
|
#include <QListIterator>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "pimpl_impl.hpp"
|
#include "pimpl_impl.hpp"
|
||||||
|
|
||||||
class FrequencyList::impl final
|
class FrequencyList::impl final
|
||||||
: public QAbstractTableModel
|
: public QAbstractTableModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
impl (Frequencies frequencies, QObject * parent)
|
impl (Frequencies frequencies, QObject * parent)
|
||||||
: QAbstractTableModel {parent}
|
: QAbstractTableModel {parent}
|
||||||
, frequencies_ {frequencies}
|
, frequencies_ {frequencies}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Frequencies const& frequencies () const {return frequencies_;}
|
Frequencies const& frequencies () const {return frequencies_;}
|
||||||
void assign (Frequencies);
|
void assign (Frequencies);
|
||||||
QModelIndex add (Frequency);
|
QModelIndex add (Frequency);
|
||||||
|
|
||||||
protected:
|
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;
|
||||||
Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override;
|
Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override;
|
||||||
QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override;
|
QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override;
|
||||||
bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override;
|
bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override;
|
||||||
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
|
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
|
||||||
bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
|
bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
|
||||||
bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
|
bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
|
||||||
QStringList mimeTypes () const override;
|
QStringList mimeTypes () const override;
|
||||||
QMimeData * mimeData (QModelIndexList const&) const override;
|
QMimeData * mimeData (QModelIndexList const&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int constexpr num_cols {2};
|
static int constexpr num_cols {2};
|
||||||
static auto constexpr mime_type ="application/wsjt.Frequencies";
|
static auto constexpr mime_type ="application/wsjt.Frequencies";
|
||||||
|
|
||||||
Frequencies frequencies_;
|
Frequencies frequencies_;
|
||||||
};
|
};
|
||||||
|
|
||||||
FrequencyList::FrequencyList (QObject * parent)
|
FrequencyList::FrequencyList (QObject * parent)
|
||||||
: FrequencyList {{}, parent}
|
: FrequencyList {{}, parent}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FrequencyList::FrequencyList (Frequencies frequencies, QObject * parent)
|
FrequencyList::FrequencyList (Frequencies frequencies, QObject * parent)
|
||||||
: QSortFilterProxyModel {parent}
|
: QSortFilterProxyModel {parent}
|
||||||
, m_ {frequencies, parent}
|
, m_ {frequencies, parent}
|
||||||
{
|
{
|
||||||
// setDynamicSortFilter (true);
|
// setDynamicSortFilter (true);
|
||||||
setSourceModel (&*m_);
|
setSourceModel (&*m_);
|
||||||
setSortRole (SortRole);
|
setSortRole (SortRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
FrequencyList::~FrequencyList ()
|
FrequencyList::~FrequencyList ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FrequencyList& FrequencyList::operator = (Frequencies frequencies)
|
FrequencyList& FrequencyList::operator = (Frequencies frequencies)
|
||||||
{
|
{
|
||||||
m_->assign (frequencies);
|
m_->assign (frequencies);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FrequencyList::frequencies () const -> Frequencies
|
auto FrequencyList::frequencies () -> Frequencies
|
||||||
{
|
{
|
||||||
return m_->frequencies ();
|
submit ();
|
||||||
}
|
return m_->frequencies ();
|
||||||
|
}
|
||||||
QModelIndex FrequencyList::add (Frequency f)
|
|
||||||
{
|
QModelIndex FrequencyList::add (Frequency f)
|
||||||
return mapFromSource (m_->add (f));
|
{
|
||||||
}
|
return mapFromSource (m_->add (f));
|
||||||
|
}
|
||||||
bool FrequencyList::remove (Frequency f)
|
|
||||||
{
|
bool FrequencyList::remove (Frequency f)
|
||||||
auto row = m_->frequencies ().indexOf (f);
|
{
|
||||||
|
auto row = m_->frequencies ().indexOf (f);
|
||||||
if (0 > row)
|
|
||||||
{
|
if (0 > row)
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
return m_->removeRow (row);
|
|
||||||
}
|
return m_->removeRow (row);
|
||||||
|
}
|
||||||
namespace
|
|
||||||
{
|
namespace
|
||||||
bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs)
|
{
|
||||||
{
|
bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs)
|
||||||
return lhs.row () > rhs.row ();
|
{
|
||||||
}
|
return lhs.row () > rhs.row ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
bool FrequencyList::removeDisjointRows (QModelIndexList rows)
|
|
||||||
{
|
bool FrequencyList::removeDisjointRows (QModelIndexList rows)
|
||||||
bool result {true};
|
{
|
||||||
|
bool result {true};
|
||||||
// We must work with source model indexes because we don't want row
|
|
||||||
// removes to invalidate model indexes we haven't yet processed. We
|
// We must work with source model indexes because we don't want row
|
||||||
// achieve that by processing them in decending row order.
|
// removes to invalidate model indexes we haven't yet processed. We
|
||||||
for (int r = 0; r < rows.size (); ++r)
|
// achieve that by processing them in decending row order.
|
||||||
{
|
for (int r = 0; r < rows.size (); ++r)
|
||||||
rows[r] = mapToSource (rows[r]);
|
{
|
||||||
}
|
rows[r] = mapToSource (rows[r]);
|
||||||
|
}
|
||||||
// reverse sort by row
|
|
||||||
qSort (rows.begin (), rows.end (), row_is_higher);
|
// reverse sort by row
|
||||||
Q_FOREACH (auto index, rows)
|
qSort (rows.begin (), rows.end (), row_is_higher);
|
||||||
{
|
Q_FOREACH (auto index, rows)
|
||||||
if (result && !m_->removeRow (index.row ()))
|
{
|
||||||
{
|
if (result && !m_->removeRow (index.row ()))
|
||||||
result = false;
|
{
|
||||||
}
|
result = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void FrequencyList::impl::assign (Frequencies frequencies)
|
|
||||||
{
|
void FrequencyList::impl::assign (Frequencies frequencies)
|
||||||
beginResetModel ();
|
{
|
||||||
std::swap (frequencies_, frequencies);
|
beginResetModel ();
|
||||||
endResetModel ();
|
std::swap (frequencies_, frequencies);
|
||||||
}
|
endResetModel ();
|
||||||
|
}
|
||||||
QModelIndex FrequencyList::impl::add (Frequency f)
|
|
||||||
{
|
QModelIndex FrequencyList::impl::add (Frequency f)
|
||||||
// Any Frequency that isn't in the list may be added
|
{
|
||||||
if (!frequencies_.contains (f))
|
// Any Frequency that isn't in the list may be added
|
||||||
{
|
if (!frequencies_.contains (f))
|
||||||
auto row = frequencies_.size ();
|
{
|
||||||
|
auto row = frequencies_.size ();
|
||||||
beginInsertRows (QModelIndex {}, row, row);
|
|
||||||
frequencies_.append (f);
|
beginInsertRows (QModelIndex {}, row, row);
|
||||||
endInsertRows ();
|
frequencies_.append (f);
|
||||||
|
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 : frequencies_.size ();
|
||||||
|
}
|
||||||
int FrequencyList::impl::columnCount (QModelIndex const& parent) const
|
|
||||||
{
|
int FrequencyList::impl::columnCount (QModelIndex const& parent) const
|
||||||
return parent.isValid () ? 0 : num_cols;
|
{
|
||||||
}
|
return parent.isValid () ? 0 : num_cols;
|
||||||
|
}
|
||||||
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 column = index.column ();
|
auto row = index.row ();
|
||||||
|
auto column = index.column ();
|
||||||
if (index.isValid ()
|
|
||||||
&& row < frequencies_.size ()
|
if (index.isValid ()
|
||||||
&& column < num_cols)
|
&& row < frequencies_.size ()
|
||||||
{
|
&& column < num_cols)
|
||||||
switch (column)
|
{
|
||||||
{
|
switch (column)
|
||||||
case 0:
|
{
|
||||||
result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
|
case 0:
|
||||||
break;
|
result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
|
||||||
|
break;
|
||||||
case 1:
|
|
||||||
result |= Qt::ItemIsDragEnabled;
|
case 1:
|
||||||
break;
|
result |= Qt::ItemIsDragEnabled;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const
|
|
||||||
{
|
QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const
|
||||||
QVariant item;
|
{
|
||||||
|
QVariant item;
|
||||||
auto row = index.row ();
|
|
||||||
auto column = index.column ();
|
auto row = index.row ();
|
||||||
|
auto column = index.column ();
|
||||||
if (index.isValid ()
|
|
||||||
&& row < frequencies_.size ()
|
if (index.isValid ()
|
||||||
&& column < num_cols)
|
&& row < frequencies_.size ()
|
||||||
{
|
&& column < num_cols)
|
||||||
auto frequency = frequencies_.at (row);
|
{
|
||||||
|
auto frequency = frequencies_.at (row);
|
||||||
switch (column)
|
|
||||||
{
|
switch (column)
|
||||||
case 0:
|
{
|
||||||
switch (role)
|
case 0:
|
||||||
{
|
switch (role)
|
||||||
case SortRole:
|
{
|
||||||
case Qt::DisplayRole:
|
case SortRole:
|
||||||
case Qt::EditRole:
|
case Qt::DisplayRole:
|
||||||
case Qt::AccessibleTextRole:
|
case Qt::EditRole:
|
||||||
item = frequency;
|
case Qt::AccessibleTextRole:
|
||||||
break;
|
item = frequency;
|
||||||
|
break;
|
||||||
case Qt::ToolTipRole:
|
|
||||||
case Qt::AccessibleDescriptionRole:
|
case Qt::ToolTipRole:
|
||||||
item = tr ("Frequency");
|
case Qt::AccessibleDescriptionRole:
|
||||||
break;
|
item = tr ("Frequency");
|
||||||
|
break;
|
||||||
case Qt::TextAlignmentRole:
|
|
||||||
item = Qt::AlignRight + Qt::AlignVCenter;
|
case Qt::TextAlignmentRole:
|
||||||
break;
|
item = Qt::AlignRight + Qt::AlignVCenter;
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
case 1:
|
|
||||||
switch (role)
|
case 1:
|
||||||
{
|
switch (role)
|
||||||
case Qt::DisplayRole:
|
{
|
||||||
case Qt::EditRole:
|
case Qt::DisplayRole:
|
||||||
case Qt::AccessibleTextRole:
|
case Qt::EditRole:
|
||||||
item = static_cast<double> (frequency / 1.e6);
|
case Qt::AccessibleTextRole:
|
||||||
break;
|
item = static_cast<double> (frequency / 1.e6);
|
||||||
|
break;
|
||||||
case SortRole: // use the underlying Frequency value
|
|
||||||
item = frequency;
|
case SortRole: // use the underlying Frequency value
|
||||||
break;
|
item = frequency;
|
||||||
|
break;
|
||||||
case Qt::ToolTipRole:
|
|
||||||
case Qt::AccessibleDescriptionRole:
|
case Qt::ToolTipRole:
|
||||||
item = tr ("Frequency MHz");
|
case Qt::AccessibleDescriptionRole:
|
||||||
break;
|
item = tr ("Frequency MHz");
|
||||||
|
break;
|
||||||
case Qt::TextAlignmentRole:
|
|
||||||
item = Qt::AlignRight + Qt::AlignVCenter;
|
case Qt::TextAlignmentRole:
|
||||||
break;
|
item = Qt::AlignRight + Qt::AlignVCenter;
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return item;
|
|
||||||
}
|
return item;
|
||||||
|
}
|
||||||
bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant const& value, int role)
|
|
||||||
{
|
bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant const& value, int role)
|
||||||
bool changed {false};
|
{
|
||||||
|
bool changed {false};
|
||||||
auto row = model_index.row ();
|
|
||||||
if (model_index.isValid ()
|
auto row = model_index.row ();
|
||||||
&& Qt::EditRole == role
|
if (model_index.isValid ()
|
||||||
&& row < frequencies_.size ()
|
&& Qt::EditRole == role
|
||||||
&& 0 == model_index.column ()
|
&& row < frequencies_.size ()
|
||||||
&& value.canConvert<Frequency> ())
|
&& 0 == model_index.column ()
|
||||||
{
|
&& value.canConvert<Frequency> ())
|
||||||
auto frequency = value.value<Frequency> ();
|
{
|
||||||
auto original_frequency = frequencies_.at (row);
|
auto frequency = value.value<Frequency> ();
|
||||||
if (frequency != original_frequency)
|
auto original_frequency = frequencies_.at (row);
|
||||||
{
|
if (frequency != original_frequency)
|
||||||
frequencies_.replace (row, frequency);
|
{
|
||||||
Q_EMIT dataChanged (model_index, index (model_index.row (), 1), QVector<int> {} << role);
|
frequencies_.replace (row, frequency);
|
||||||
}
|
Q_EMIT dataChanged (model_index, index (model_index.row (), 1), QVector<int> {} << role);
|
||||||
changed = true;
|
}
|
||||||
}
|
changed = true;
|
||||||
|
}
|
||||||
return changed;
|
|
||||||
}
|
return changed;
|
||||||
|
}
|
||||||
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
|
|
||||||
&& Qt::Horizontal == orientation
|
if (Qt::DisplayRole == role
|
||||||
&& section < num_cols)
|
&& Qt::Horizontal == orientation
|
||||||
{
|
&& section < num_cols)
|
||||||
switch (section)
|
{
|
||||||
{
|
switch (section)
|
||||||
case 0: header = tr ("Frequency"); break;
|
{
|
||||||
case 1: header = tr ("Frequency (MHz)"); break;
|
case 0: header = tr ("Frequency"); break;
|
||||||
}
|
case 1: header = tr ("Frequency (MHz)"); break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
header = QAbstractTableModel::headerData (section, orientation, role);
|
{
|
||||||
}
|
header = QAbstractTableModel::headerData (section, orientation, role);
|
||||||
|
}
|
||||||
return header;
|
|
||||||
}
|
return header;
|
||||||
|
}
|
||||||
bool FrequencyList::impl::removeRows (int row, int count, QModelIndex const& parent)
|
|
||||||
{
|
bool FrequencyList::impl::removeRows (int row, int count, QModelIndex const& parent)
|
||||||
if (0 < count && (row + count) <= rowCount (parent))
|
{
|
||||||
{
|
if (0 < count && (row + count) <= rowCount (parent))
|
||||||
beginRemoveRows (parent, row, row + count - 1);
|
{
|
||||||
for (auto r = 0; r < count; ++r)
|
beginRemoveRows (parent, row, row + count - 1);
|
||||||
{
|
for (auto r = 0; r < count; ++r)
|
||||||
frequencies_.removeAt (row);
|
{
|
||||||
}
|
frequencies_.removeAt (row);
|
||||||
endRemoveRows ();
|
}
|
||||||
return true;
|
endRemoveRows ();
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
return false;
|
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
bool FrequencyList::impl::insertRows (int row, int count, QModelIndex const& parent)
|
|
||||||
{
|
bool FrequencyList::impl::insertRows (int row, int count, QModelIndex const& parent)
|
||||||
if (0 < count)
|
{
|
||||||
{
|
if (0 < count)
|
||||||
beginInsertRows (parent, row, row + count - 1);
|
{
|
||||||
for (auto r = 0; r < count; ++r)
|
beginInsertRows (parent, row, row + count - 1);
|
||||||
{
|
for (auto r = 0; r < count; ++r)
|
||||||
frequencies_.insert (row, Frequency {});
|
{
|
||||||
}
|
frequencies_.insert (row, Frequency {});
|
||||||
endInsertRows ();
|
}
|
||||||
return true;
|
endInsertRows ();
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
return false;
|
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
QStringList FrequencyList::impl::mimeTypes () const
|
|
||||||
{
|
QStringList FrequencyList::impl::mimeTypes () const
|
||||||
QStringList types;
|
{
|
||||||
types << mime_type;
|
QStringList types;
|
||||||
return types;
|
types << mime_type;
|
||||||
}
|
return types;
|
||||||
|
}
|
||||||
QMimeData * FrequencyList::impl::mimeData (QModelIndexList const& items) const
|
|
||||||
{
|
QMimeData * FrequencyList::impl::mimeData (QModelIndexList const& items) const
|
||||||
QMimeData * mime_data = new QMimeData {};
|
{
|
||||||
QByteArray encoded_data;
|
QMimeData * mime_data = new QMimeData {};
|
||||||
QDataStream stream {&encoded_data, QIODevice::WriteOnly};
|
QByteArray encoded_data;
|
||||||
|
QDataStream stream {&encoded_data, QIODevice::WriteOnly};
|
||||||
Q_FOREACH (auto const& item, items)
|
|
||||||
{
|
Q_FOREACH (auto const& item, items)
|
||||||
if (item.isValid ())
|
{
|
||||||
{
|
if (item.isValid ())
|
||||||
stream << QString {data (item, Qt::DisplayRole).toString ()};
|
{
|
||||||
}
|
stream << QString {data (item, Qt::DisplayRole).toString ()};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mime_data->setData (mime_type, encoded_data);
|
|
||||||
return mime_data;
|
mime_data->setData (mime_type, encoded_data);
|
||||||
}
|
return mime_data;
|
||||||
|
}
|
||||||
|
@ -1,59 +1,59 @@
|
|||||||
#ifndef FREQUENCY_LIST_HPP__
|
#ifndef FREQUENCY_LIST_HPP__
|
||||||
#define FREQUENCY_LIST_HPP__
|
#define FREQUENCY_LIST_HPP__
|
||||||
|
|
||||||
#include "pimpl_h.hpp"
|
#include "pimpl_h.hpp"
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
#include "Radio.hpp"
|
#include "Radio.hpp"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Class FrequencyList
|
// Class FrequencyList
|
||||||
//
|
//
|
||||||
// Encapsulates a collection of frequencies. The implementation is a
|
// Encapsulates a collection of frequencies. The implementation is a
|
||||||
// table containing the list of Frequency type elements which is
|
// table containing the list of Frequency type elements which is
|
||||||
// editable and a second column which is an immutable double
|
// editable and a second column which is an immutable double
|
||||||
// representation of the corresponding Frequency item scaled to
|
// representation of the corresponding Frequency item scaled to
|
||||||
// mega-Hertz.
|
// mega-Hertz.
|
||||||
//
|
//
|
||||||
// The list is ordered.
|
// The list is ordered.
|
||||||
//
|
//
|
||||||
// Responsibilities
|
// Responsibilities
|
||||||
//
|
//
|
||||||
// Stores internally a list of unique frequencies. Provides methods
|
// Stores internally a list of unique frequencies. Provides methods
|
||||||
// to add and delete list elements.
|
// to add and delete list elements.
|
||||||
//
|
//
|
||||||
// Collaborations
|
// Collaborations
|
||||||
//
|
//
|
||||||
// Implements the QSortFilterProxyModel interface for a list of spot
|
// Implements the QSortFilterProxyModel interface for a list of spot
|
||||||
// frequencies.
|
// frequencies.
|
||||||
//
|
//
|
||||||
class FrequencyList final
|
class FrequencyList final
|
||||||
: public QSortFilterProxyModel
|
: public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Frequency = Radio::Frequency;
|
using Frequency = Radio::Frequency;
|
||||||
using Frequencies = Radio::Frequencies;
|
using Frequencies = Radio::Frequencies;
|
||||||
|
|
||||||
explicit FrequencyList (QObject * parent = nullptr);
|
explicit FrequencyList (QObject * parent = nullptr);
|
||||||
explicit FrequencyList (Frequencies, QObject * parent = nullptr);
|
explicit FrequencyList (Frequencies, QObject * parent = nullptr);
|
||||||
~FrequencyList ();
|
~FrequencyList ();
|
||||||
|
|
||||||
// Load and store contents
|
// Load and store contents
|
||||||
FrequencyList& operator = (Frequencies);
|
FrequencyList& operator = (Frequencies);
|
||||||
Frequencies frequencies () const;
|
Frequencies frequencies ();
|
||||||
|
|
||||||
// Model API
|
// Model API
|
||||||
QModelIndex add (Frequency);
|
QModelIndex add (Frequency);
|
||||||
bool remove (Frequency);
|
bool remove (Frequency);
|
||||||
bool removeDisjointRows (QModelIndexList);
|
bool removeDisjointRows (QModelIndexList);
|
||||||
|
|
||||||
// Custom roles.
|
// Custom roles.
|
||||||
static int constexpr SortRole = Qt::UserRole;
|
static int constexpr SortRole = Qt::UserRole;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
pimpl<impl> m_;
|
pimpl<impl> m_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
1103
StationList.cpp
1103
StationList.cpp
File diff suppressed because it is too large
Load Diff
198
StationList.hpp
198
StationList.hpp
@ -1,96 +1,102 @@
|
|||||||
#ifndef STATION_LIST_HPP__
|
#ifndef STATION_LIST_HPP__
|
||||||
#define STATION_LIST_HPP__
|
#define STATION_LIST_HPP__
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
#include "pimpl_h.hpp"
|
#include "pimpl_h.hpp"
|
||||||
|
|
||||||
#include "Radio.hpp"
|
#include "Radio.hpp"
|
||||||
|
|
||||||
class Bands;
|
class Bands;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Class StationList
|
// Class StationList
|
||||||
//
|
//
|
||||||
// Encapsulates information about a collection of unique operating
|
// Encapsulates information about a collection of unique operating
|
||||||
// stations per band. The implementation is a table model with the
|
// stations per band. The implementation is a table model with the
|
||||||
// first column being the unique (within the table rows) band name
|
// first column being the unique (within the table rows) band name
|
||||||
// and, the second the frequency offset for transverter usage and,
|
// and, the second the frequency offset for transverter usage and,
|
||||||
// the third the antenna description. All are editable.
|
// the third the antenna description. All are editable.
|
||||||
//
|
//
|
||||||
// Responsibilities
|
// Responsibilities
|
||||||
//
|
//
|
||||||
// Stores internally an unordered table of bands.
|
// Stores internally an unordered table of bands.
|
||||||
//
|
//
|
||||||
// If an ordered representaion is required then wrapping with an
|
// If an ordered representaion is required then wrapping with an
|
||||||
// appropriate proxy model is sufficient
|
// appropriate proxy model is sufficient
|
||||||
// e.g. QSortFilterProxyModel. A custom SortRole role is provided for
|
// e.g. QSortFilterProxyModel. A custom SortRole role is provided for
|
||||||
// the band name column which returns a numeric value (Bands lower
|
// the band name column which returns a numeric value (Bands lower
|
||||||
// frequency limit) which gives a strict frequency ordering by band.
|
// frequency limit) which gives a strict frequency ordering by band.
|
||||||
//
|
//
|
||||||
// Collaborations
|
// Collaborations
|
||||||
//
|
//
|
||||||
// Implements the QAbstractTableModel interface for a grid of bands
|
// Implements the QAbstractTableModel interface for a grid of bands
|
||||||
// with offset frequencies and antenna descriptions.
|
// with offset frequencies and antenna descriptions.
|
||||||
//
|
//
|
||||||
// Uses the QAbstractItemModel interface of the bands model to lookup
|
// Uses the QAbstractItemModel interface of the bands model to lookup
|
||||||
// band information.
|
// band information.
|
||||||
//
|
//
|
||||||
class StationList final
|
class StationList final
|
||||||
: public QSortFilterProxyModel
|
: public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Frequency = Radio::Frequency;
|
using Frequency = Radio::Frequency;
|
||||||
using FrequencyDelta = Radio::FrequencyDelta;
|
using FrequencyDelta = Radio::FrequencyDelta;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Struct Station
|
// Struct Station
|
||||||
//
|
//
|
||||||
// Aggregation of fields that describe a radio station on a band.
|
// Aggregation of fields that describe a radio station on a band.
|
||||||
//
|
//
|
||||||
struct Station
|
struct Station
|
||||||
{
|
{
|
||||||
QString band_name_;
|
QString band_name_;
|
||||||
FrequencyDelta offset_;
|
FrequencyDelta offset_;
|
||||||
QString antenna_description_;
|
QString antenna_description_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Stations = QList<Station>;
|
using Stations = QList<Station>;
|
||||||
|
|
||||||
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 store contents.
|
||||||
StationList& operator = (Stations);
|
StationList& operator = (Stations);
|
||||||
Stations stations () const;
|
Stations stations ();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Model API
|
// Model API
|
||||||
//
|
//
|
||||||
QModelIndex add (Station); // Add a new Station
|
QModelIndex add (Station); // Add a new Station
|
||||||
bool remove (Station); // Remove a Station
|
bool remove (Station); // Remove a Station
|
||||||
bool removeDisjointRows (QModelIndexList); // Remove one or more stations
|
bool removeDisjointRows (QModelIndexList); // Remove one or more stations
|
||||||
FrequencyDelta offset (Frequency) const; // Return the offset to be used for a Frequency
|
FrequencyDelta offset (Frequency) const; // Return the offset to be used for a Frequency
|
||||||
|
|
||||||
// Custom sort role.
|
// Custom sort role.
|
||||||
static int constexpr SortRole = Qt::UserRole;
|
static int constexpr SortRole = Qt::UserRole;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
pimpl<impl> m_;
|
pimpl<impl> m_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Station equivalence is based on band name alone.
|
// Station equivalence
|
||||||
inline
|
inline
|
||||||
bool operator == (StationList::Station const& lhs, StationList::Station const& rhs)
|
bool operator == (StationList::Station const& lhs, StationList::Station const& rhs)
|
||||||
{
|
{
|
||||||
return lhs.band_name_ == rhs.band_name_;
|
return lhs.band_name_ == rhs.band_name_
|
||||||
}
|
&& lhs.offset_ == rhs.offset_
|
||||||
|
&& lhs.antenna_description_ == rhs.antenna_description_;
|
||||||
Q_DECLARE_METATYPE (StationList::Station);
|
}
|
||||||
Q_DECLARE_METATYPE (StationList::Stations);
|
|
||||||
|
Q_DECLARE_METATYPE (StationList::Station);
|
||||||
#endif
|
Q_DECLARE_METATYPE (StationList::Stations);
|
||||||
|
|
||||||
|
#if !defined (QT_NO_DEBUG_STREAM)
|
||||||
|
QDebug operator << (QDebug debug, StationList::Station const&);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user