| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | #include "StationList.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <utility>
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QMetaType>
 | 
					
						
							|  |  |  | #include <QAbstractTableModel>
 | 
					
						
							|  |  |  | #include <QObject>
 | 
					
						
							|  |  |  | #include <QString>
 | 
					
						
							|  |  |  | #include <QVector>
 | 
					
						
							|  |  |  | #include <QStringList>
 | 
					
						
							|  |  |  | #include <QMimeData>
 | 
					
						
							|  |  |  | #include <QDataStream>
 | 
					
						
							|  |  |  | #include <QByteArray>
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | #include <QDebugStateSaver>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "pimpl_impl.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Radio.hpp"
 | 
					
						
							|  |  |  | #include "Bands.hpp"
 | 
					
						
							|  |  |  | #include "FrequencyList.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (QT_NO_DEBUG_STREAM)
 | 
					
						
							|  |  |  | QDebug operator << (QDebug debug, StationList::Station const& station) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QDebugStateSaver saver {debug}; | 
					
						
							|  |  |  |   debug.nospace () << "Station(" | 
					
						
							|  |  |  |                    << station.band_name_ << ", " | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |                    << station.frequency_ << ", " | 
					
						
							|  |  |  |                    << station.switch_at_ << ", " | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |                    << station.switch_until_ << ", " | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |                    << station.description_ << ')'; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |   return debug; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QDataStream& operator << (QDataStream& os, StationList::Station const& station) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return os << station.band_name_ | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             << station.frequency_ | 
					
						
							|  |  |  |             << station.switch_at_ | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |             << station.switch_until_ | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |             << station.description_; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QDataStream& operator >> (QDataStream& is, StationList::Station& station) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return is >> station.band_name_ | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             >> station.frequency_ | 
					
						
							|  |  |  |             >> station.switch_at_ | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |             >> station.switch_until_ | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |             >> station.description_; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StationList::impl final | 
					
						
							|  |  |  |   : public QAbstractTableModel | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |   impl (Bands const * bands, Stations stations, QObject * parent) | 
					
						
							|  |  |  |     : QAbstractTableModel {parent} | 
					
						
							|  |  |  |     , bands_ {bands} | 
					
						
							|  |  |  |     , stations_ {stations} | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Stations station_list (Stations); | 
					
						
							|  |  |  |   QModelIndex add (Station); | 
					
						
							|  |  |  |   FrequencyDelta offset (Frequency) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Implement the QAbstractTableModel interface.
 | 
					
						
							|  |  |  |   int rowCount (QModelIndex const& parent = QModelIndex {}) const override; | 
					
						
							|  |  |  |   int columnCount (QModelIndex const& parent = QModelIndex {}) const override; | 
					
						
							|  |  |  |   Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; | 
					
						
							|  |  |  |   QVariant data (QModelIndex const&, int role) const override; | 
					
						
							|  |  |  |   QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; | 
					
						
							|  |  |  |   bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; | 
					
						
							|  |  |  |   bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; | 
					
						
							|  |  |  |   bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; | 
					
						
							|  |  |  |   Qt::DropActions supportedDropActions () const override; | 
					
						
							|  |  |  |   QStringList mimeTypes () const override; | 
					
						
							|  |  |  |   QMimeData * mimeData (QModelIndexList const&) const override; | 
					
						
							|  |  |  |   bool dropMimeData (QMimeData const *, Qt::DropAction, int row, int column, QModelIndex const& parent) override; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Helper method for band validation.
 | 
					
						
							|  |  |  |   QModelIndex first_matching_band (QString const& band_name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // find first exact match in bands
 | 
					
						
							|  |  |  |     auto matches = bands_->match (bands_->index (0, 0) | 
					
						
							|  |  |  |                                   , Qt::DisplayRole | 
					
						
							|  |  |  |                                   , band_name | 
					
						
							|  |  |  |                                   , 1 | 
					
						
							|  |  |  |                                   , Qt::MatchExactly); | 
					
						
							|  |  |  |     return matches.isEmpty () ? QModelIndex {} : matches.first (); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |   static int constexpr num_columns {5}; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |   static auto constexpr mime_type = "application/wsjt.antenna-descriptions"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Bands const * bands_; | 
					
						
							|  |  |  |   Stations stations_; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StationList::StationList (Bands const * bands, QObject * parent) | 
					
						
							|  |  |  |   : StationList {bands, {}, parent} | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StationList::StationList (Bands const * bands, Stations stations, QObject * parent) | 
					
						
							|  |  |  |   : QSortFilterProxyModel {parent} | 
					
						
							|  |  |  |   , m_ {bands, stations, parent} | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   setSourceModel (&*m_); | 
					
						
							|  |  |  |   setSortRole (SortRole); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StationList::~StationList () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | auto StationList::station_list (Stations stations) -> Stations | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_->station_list (stations); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | auto StationList::station_list () const -> Stations const& | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_->stations_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QModelIndex StationList::add (Station s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return mapFromSource (m_->add (s)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StationList::remove (Station s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto row = m_->stations_.indexOf (s); | 
					
						
							|  |  |  |   if (0 > row) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return removeRow (row); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return lhs.row () > rhs.row (); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StationList::removeDisjointRows (QModelIndexList rows) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   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
 | 
					
						
							|  |  |  |   // achieve that by processing them in decending row order.
 | 
					
						
							|  |  |  |   for (int r = 0; r < rows.size (); ++r) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       rows[r] = mapToSource (rows[r]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // reverse sort by row
 | 
					
						
							|  |  |  |   qSort (rows.begin (), rows.end (), row_is_higher); | 
					
						
							|  |  |  |   Q_FOREACH (auto index, rows) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (result && !m_->removeRow (index.row ())) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           result = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | auto StationList::impl::station_list (Stations stations) -> Stations | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   beginResetModel (); | 
					
						
							|  |  |  |   std::swap (stations_, stations); | 
					
						
							|  |  |  |   endResetModel (); | 
					
						
							|  |  |  |   return stations; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QModelIndex StationList::impl::add (Station s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // Any band that isn't in the list may be added
 | 
					
						
							|  |  |  |   if (!stations_.contains (s)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       auto row = stations_.size (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beginInsertRows (QModelIndex {}, row, row); | 
					
						
							|  |  |  |       stations_.append (s); | 
					
						
							|  |  |  |       endInsertRows (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return index (row, 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return QModelIndex {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | auto StationList::impl::offset (Frequency f) const -> FrequencyDelta | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // Lookup band for frequency
 | 
					
						
							|  |  |  |   auto const& band = bands_->find (f); | 
					
						
							|  |  |  |   if (!band.isEmpty ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Lookup station for band
 | 
					
						
							|  |  |  |       for (int i = 0; i < stations_.size (); ++i) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           if (stations_[i].band_name_ == band) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |               return stations_[i].frequency_; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return 0;                     // no offset
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | int StationList::impl::rowCount (QModelIndex const& parent) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return parent.isValid () ? 0 : stations_.size (); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int StationList::impl::columnCount (QModelIndex const& parent) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return parent.isValid () ? 0 : num_columns; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Qt::ItemFlags StationList::impl::flags (QModelIndex const& index) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto result = QAbstractTableModel::flags (index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto row = index.row (); | 
					
						
							|  |  |  |   auto column = index.column (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (index.isValid () | 
					
						
							|  |  |  |       && row < stations_.size () | 
					
						
							|  |  |  |       && column < num_columns) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |       if (band_column == column){ | 
					
						
							|  |  |  |           result |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       } else if (description_column == column) | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |         { | 
					
						
							|  |  |  |           result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           result |= Qt::ItemIsEditable | Qt::ItemIsDropEnabled; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       result |= Qt::ItemIsDropEnabled; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QVariant StationList::impl::data (QModelIndex const& index, int role) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QVariant item; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto row = index.row (); | 
					
						
							|  |  |  |   auto column = index.column (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (index.isValid () | 
					
						
							|  |  |  |       && row < stations_.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       switch (column) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case band_column: | 
					
						
							|  |  |  |           switch (role) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case SortRole: | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 // Lookup band.
 | 
					
						
							|  |  |  |                 auto band_index = first_matching_band (stations_.at (row).band_name_); | 
					
						
							|  |  |  |                 // Use the sort role value of the band.
 | 
					
						
							|  |  |  |                 item = band_index.data (Bands::SortRole); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case Qt::DisplayRole: | 
					
						
							|  |  |  |             case Qt::EditRole: | 
					
						
							|  |  |  |             case Qt::AccessibleTextRole: | 
					
						
							|  |  |  |               item = stations_.at (row).band_name_; | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case Qt::ToolTipRole: | 
					
						
							|  |  |  |             case Qt::AccessibleDescriptionRole: | 
					
						
							|  |  |  |               item = tr ("Band name"); | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case Qt::TextAlignmentRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |               item = (int)Qt::AlignHCenter | Qt::AlignVCenter; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |         case frequency_column: | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |           { | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             auto frequency_offset = stations_.at (row).frequency_; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |             switch (role) | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |               case SortRole: | 
					
						
							|  |  |  |               case Qt::EditRole: | 
					
						
							|  |  |  |               case Qt::AccessibleTextRole: | 
					
						
							|  |  |  |                 item = frequency_offset; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               case Qt::DisplayRole: | 
					
						
							|  |  |  |                 item = Radio::pretty_frequency_MHz_string (frequency_offset) + " MHz"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               case Qt::ToolTipRole: | 
					
						
							|  |  |  |               case Qt::AccessibleDescriptionRole: | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |                 item = tr ("Frequency"); | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               case Qt::TextAlignmentRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |                 item = (int)Qt::AlignRight | Qt::AlignVCenter; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |                 break; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |       case switch_at_column: | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |         switch (role) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |           case SortRole: | 
					
						
							|  |  |  |           case Qt::EditRole: | 
					
						
							|  |  |  |           case Qt::DisplayRole: | 
					
						
							|  |  |  |           case Qt::AccessibleTextRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |             item = stations_.at (row).switch_at_.time().toString("hh:mm"); | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           case Qt::ToolTipRole: | 
					
						
							|  |  |  |           case Qt::AccessibleDescriptionRole: | 
					
						
							|  |  |  |             item = tr ("Switch at this time"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           case Qt::TextAlignmentRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |             item = (int)Qt::AlignHCenter | Qt::AlignVCenter; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case switch_until_column: | 
					
						
							|  |  |  |         switch (role) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |           case SortRole: | 
					
						
							|  |  |  |           case Qt::EditRole: | 
					
						
							|  |  |  |           case Qt::DisplayRole: | 
					
						
							|  |  |  |           case Qt::AccessibleTextRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |             item = stations_.at (row).switch_until_.time().toString("hh:mm"); | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           case Qt::ToolTipRole: | 
					
						
							|  |  |  |           case Qt::AccessibleDescriptionRole: | 
					
						
							|  |  |  |             item = tr ("Switch until this time"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           case Qt::TextAlignmentRole: | 
					
						
							|  |  |  |             item = (int)Qt::AlignHCenter | Qt::AlignVCenter; | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |       case description_column: | 
					
						
							|  |  |  |         switch (role) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |           case SortRole: | 
					
						
							|  |  |  |           case Qt::EditRole: | 
					
						
							|  |  |  |           case Qt::DisplayRole: | 
					
						
							|  |  |  |           case Qt::AccessibleTextRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |             item = stations_.at (row).description_; | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           case Qt::ToolTipRole: | 
					
						
							|  |  |  |           case Qt::AccessibleDescriptionRole: | 
					
						
							|  |  |  |             item = tr ("Antenna description"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           case Qt::TextAlignmentRole: | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |             item = (int)Qt::AlignLeft | Qt::AlignVCenter; | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return item; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QVariant StationList::impl::headerData (int section, Qt::Orientation orientation, int role) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QVariant header; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (Qt::DisplayRole == role && Qt::Horizontal == orientation) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       switch (section) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case band_column: header = tr ("Band"); break; | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |         case frequency_column: header = tr ("Freq. (MHz)"); break; | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |         case switch_at_column: header = tr ("Switch at (UTC)"); break; | 
					
						
							|  |  |  |         case switch_until_column: header = tr ("Until (UTC)"); break; | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |         case description_column: header = tr ("Description"); break; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       header = QAbstractTableModel::headerData (section, orientation, role); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return header; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StationList::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   bool changed {false}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto row = model_index.row (); | 
					
						
							|  |  |  |   auto size = stations_.size (); | 
					
						
							|  |  |  |   if (model_index.isValid () | 
					
						
							|  |  |  |       && Qt::EditRole == role | 
					
						
							|  |  |  |       && row < size) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QVector<int> roles; | 
					
						
							|  |  |  |       roles << role; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       switch (model_index.column ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case band_column: | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             // Check if band name is valid.
 | 
					
						
							|  |  |  |             auto band_index = first_matching_band (value.toString ()); | 
					
						
							|  |  |  |             if (band_index.isValid ()) | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 stations_[row].band_name_ = band_index.data ().toString (); | 
					
						
							|  |  |  |                 Q_EMIT dataChanged (model_index, model_index, roles); | 
					
						
							|  |  |  |                 changed = true; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |         case frequency_column: | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |           { | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |             if (value.canConvert<Frequency> ()) | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |               { | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |                 Frequency offset {qvariant_cast<Radio::Frequency> (value)}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if(offset == 0){ | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |                     Frequency l; | 
					
						
							|  |  |  |                     Frequency h; | 
					
						
							|  |  |  |                     if(bands_->findFreq(stations_[row].band_name_, &l, &h)){ | 
					
						
							|  |  |  |                         offset = l; | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (offset != stations_[row].frequency_) | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |                   { | 
					
						
							| 
									
										
										
										
											2018-08-09 15:28:23 -04:00
										 |  |  |                     stations_[row].frequency_ = offset; | 
					
						
							|  |  |  |                     Q_EMIT dataChanged (model_index, model_index, roles); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |                     auto band = bands_->find(offset); | 
					
						
							|  |  |  |                     if(band != stations_[row].band_name_){ | 
					
						
							|  |  |  |                         stations_[row].band_name_ = band; | 
					
						
							| 
									
										
										
										
											2018-08-09 15:28:23 -04:00
										 |  |  |                         auto band_index = model_index.model()->index(row, band_column, model_index); | 
					
						
							|  |  |  |                         Q_EMIT dataChanged (band_index, band_index, roles); | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |                     changed = true; | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |         case switch_at_column: | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |         { | 
					
						
							|  |  |  |           QString s = value.toString(); | 
					
						
							|  |  |  |           if(s.length() < 5){ | 
					
						
							|  |  |  |               s = QString("0").repeated(5-s.length()) + s; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           auto t = QTime::fromString(s); | 
					
						
							| 
									
										
										
										
											2018-08-09 12:52:48 -04:00
										 |  |  |           auto at = QDateTime(QDate(2000,1,1), t, Qt::UTC); | 
					
						
							|  |  |  |           auto until = stations_[row].switch_until_; | 
					
						
							| 
									
										
										
										
											2018-08-11 09:39:02 -04:00
										 |  |  |           stations_[row].switch_at_ = at; | 
					
						
							|  |  |  |           stations_[row].switch_until_ = until; | 
					
						
							| 
									
										
										
										
											2018-08-09 12:52:48 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |           Q_EMIT dataChanged (model_index, model_index, roles); | 
					
						
							| 
									
										
										
										
											2018-08-09 15:28:23 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |           auto switch_until_index = model_index.model()->index(row, switch_until_column, model_index); | 
					
						
							|  |  |  |           Q_EMIT dataChanged (switch_until_index, switch_until_index, roles); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 23:19:27 -04:00
										 |  |  |           changed = true; | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |         case switch_until_column: | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |         { | 
					
						
							|  |  |  |           QString s = value.toString(); | 
					
						
							|  |  |  |           if(s.length() < 5){ | 
					
						
							|  |  |  |               s = QString("0").repeated(5-s.length()) + s; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           auto t = QTime::fromString(s); | 
					
						
							| 
									
										
										
										
											2018-08-09 12:52:48 -04:00
										 |  |  |           auto until = QDateTime(QDate(2000,1,1), t, Qt::UTC); | 
					
						
							|  |  |  |           auto at = stations_[row].switch_at_; | 
					
						
							| 
									
										
										
										
											2018-08-11 09:39:02 -04:00
										 |  |  |           stations_[row].switch_at_ = at; | 
					
						
							|  |  |  |           stations_[row].switch_until_ = until; | 
					
						
							| 
									
										
										
										
											2018-08-09 12:52:48 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |           Q_EMIT dataChanged (model_index, model_index, roles); | 
					
						
							| 
									
										
										
										
											2018-08-09 15:28:23 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |           auto switch_at_index = model_index.model()->index(row, switch_at_column, model_index); | 
					
						
							|  |  |  |           Q_EMIT dataChanged (switch_at_index, switch_at_index, roles); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |           changed = true; | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |         case description_column: | 
					
						
							| 
									
										
										
										
											2018-08-09 09:44:22 -04:00
										 |  |  |           stations_[row].description_ = value.toString (); | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |           Q_EMIT dataChanged (model_index, model_index, roles); | 
					
						
							|  |  |  |           changed = true; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return changed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StationList::impl::removeRows (int row, int count, QModelIndex const& parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (0 < count && (row + count) <= rowCount (parent)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       beginRemoveRows (parent, row, row + count - 1); | 
					
						
							|  |  |  |       for (auto r = 0; r < count; ++r) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           stations_.removeAt (row); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       endRemoveRows (); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StationList::impl::insertRows (int row, int count, QModelIndex const& parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (0 < count) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       beginInsertRows (parent, row, row + count - 1); | 
					
						
							|  |  |  |       for (auto r = 0; r < count; ++r) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           stations_.insert (row, Station ()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       endInsertRows (); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Qt::DropActions StationList::impl::supportedDropActions () const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return Qt::CopyAction | Qt::MoveAction; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QStringList StationList::impl::mimeTypes () const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QStringList types; | 
					
						
							|  |  |  |   types << mime_type; | 
					
						
							|  |  |  |   types << "application/wsjt.Frequencies"; | 
					
						
							|  |  |  |   return types; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QMimeData * StationList::impl::mimeData (QModelIndexList const& items) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QMimeData * mime_data = new QMimeData {}; | 
					
						
							|  |  |  |   QByteArray encoded_data; | 
					
						
							|  |  |  |   QDataStream stream {&encoded_data, QIODevice::WriteOnly}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Q_FOREACH (auto const& item, items) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (item.isValid ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           stream << QString {data (item, Qt::DisplayRole).toString ()}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mime_data->setData (mime_type, encoded_data); | 
					
						
							|  |  |  |   return mime_data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction action, int /* row */, int /* column */, QModelIndex const& parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (Qt::IgnoreAction == action) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   if (parent.isValid () | 
					
						
							|  |  |  |       && description_column == parent.column () | 
					
						
							|  |  |  |       && data->hasFormat (mime_type)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray encoded_data {data->data (mime_type)}; | 
					
						
							|  |  |  |       QDataStream stream {&encoded_data, QIODevice::ReadOnly}; | 
					
						
							|  |  |  |       auto dest_index = parent; | 
					
						
							|  |  |  |       while (!stream.atEnd ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           QString text; | 
					
						
							|  |  |  |           stream >> text; | 
					
						
							|  |  |  |           setData (dest_index, text); | 
					
						
							|  |  |  |           dest_index = index (dest_index.row () + 1, dest_index.column (), QModelIndex {}); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else if (data->hasFormat ("application/wsjt.Frequencies")) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray encoded_data {data->data ("application/wsjt.Frequencies")}; | 
					
						
							|  |  |  |       QDataStream stream {&encoded_data, QIODevice::ReadOnly}; | 
					
						
							|  |  |  |       while (!stream.atEnd ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           FrequencyList_v2::Item item; | 
					
						
							|  |  |  |           stream >> item; | 
					
						
							|  |  |  |           auto const& band = bands_->find (item.frequency_); | 
					
						
							|  |  |  |           if (stations_.cend () == std::find_if (stations_.cbegin () | 
					
						
							|  |  |  |                                                  , stations_.cend () | 
					
						
							|  |  |  |                                                  , [&band] (Station const& s) {return s.band_name_ == band;})) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               // not found so add it
 | 
					
						
							| 
									
										
										
										
											2018-08-09 00:06:02 -04:00
										 |  |  |               add (Station {band, 0, QDateTime::currentDateTimeUtc(), QDateTime::currentDateTimeUtc(), QString {}}); | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } |