2023-09-28 11:45:35 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
2023-11-18 06:02:48 -05:00
|
|
|
// Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
2023-09-28 11:45:35 -04:00
|
|
|
// //
|
|
|
|
// This program is free software; you can redistribute it and/or modify //
|
|
|
|
// it under the terms of the GNU General Public License as published by //
|
|
|
|
// the Free Software Foundation as version 3 of the License, or //
|
|
|
|
// (at your option) any later version. //
|
|
|
|
// //
|
|
|
|
// This program is distributed in the hope that it will be useful, //
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
|
|
// GNU General Public License V3 for more details. //
|
|
|
|
// //
|
|
|
|
// You should have received a copy of the GNU General Public License //
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QAction>
|
|
|
|
#include <QClipboard>
|
|
|
|
#include <QMenu>
|
|
|
|
#include <QTableWidget>
|
|
|
|
#include <QTableWidgetItem>
|
2023-11-29 12:13:34 -05:00
|
|
|
#include <QComboBox>
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
#include "device/deviceset.h"
|
|
|
|
#include "device/deviceuiset.h"
|
|
|
|
#include "dsp/dspengine.h"
|
|
|
|
#include "dsp/dspcommands.h"
|
|
|
|
#include "ui_freqscannergui.h"
|
|
|
|
#include "util/simpleserializer.h"
|
|
|
|
#include "util/db.h"
|
|
|
|
#include "gui/basicchannelsettingsdialog.h"
|
|
|
|
#include "dsp/dspengine.h"
|
|
|
|
#include "dsp/glscopesettings.h"
|
|
|
|
#include "gui/tabletapandhold.h"
|
|
|
|
#include "gui/dialogpositioner.h"
|
|
|
|
#include "gui/decimaldelegate.h"
|
|
|
|
#include "gui/frequencydelegate.h"
|
2023-11-29 12:13:34 -05:00
|
|
|
#include "gui/int64delegate.h"
|
2023-09-28 11:45:35 -04:00
|
|
|
#include "gui/glspectrum.h"
|
|
|
|
#include "channel/channelwebapiutils.h"
|
2023-12-05 07:32:53 -05:00
|
|
|
#include "maincore.h"
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
#include "freqscannergui.h"
|
|
|
|
#include "freqscanneraddrangedialog.h"
|
|
|
|
#include "freqscanner.h"
|
|
|
|
#include "freqscannersink.h"
|
|
|
|
|
|
|
|
FreqScannerGUI* FreqScannerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
|
|
|
|
{
|
|
|
|
FreqScannerGUI* gui = new FreqScannerGUI(pluginAPI, deviceUISet, rxChannel);
|
|
|
|
return gui;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::destroy()
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::resetToDefaults()
|
|
|
|
{
|
|
|
|
m_settings.resetToDefaults();
|
|
|
|
displaySettings();
|
|
|
|
applyAllSettings();
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray FreqScannerGUI::serialize() const
|
|
|
|
{
|
|
|
|
return m_settings.serialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FreqScannerGUI::deserialize(const QByteArray& data)
|
|
|
|
{
|
|
|
|
if(m_settings.deserialize(data))
|
|
|
|
{
|
|
|
|
displaySettings();
|
|
|
|
applyAllSettings();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
resetToDefaults();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FreqScannerGUI::handleMessage(const Message& message)
|
|
|
|
{
|
|
|
|
if (FreqScanner::MsgConfigureFreqScanner::match(message))
|
|
|
|
{
|
|
|
|
qDebug("FreqScannerGUI::handleMessage: FreqScanner::MsgConfigureFreqScanner");
|
|
|
|
const FreqScanner::MsgConfigureFreqScanner& cfg = (FreqScanner::MsgConfigureFreqScanner&) message;
|
|
|
|
m_settings = cfg.getSettings();
|
|
|
|
blockApplySettings(true);
|
|
|
|
m_channelMarker.updateSettings(static_cast<const ChannelMarker*>(m_settings.m_channelMarker));
|
|
|
|
displaySettings();
|
|
|
|
blockApplySettings(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (DSPSignalNotification::match(message))
|
|
|
|
{
|
|
|
|
DSPSignalNotification& notif = (DSPSignalNotification&) message;
|
|
|
|
m_deviceCenterFrequency = notif.getCenterFrequency();
|
|
|
|
m_basebandSampleRate = notif.getSampleRate();
|
2023-10-13 03:54:43 -04:00
|
|
|
if (m_basebandSampleRate != 0)
|
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->deltaFrequency->setValueRange(true, 8, 0, m_basebandSampleRate/2);
|
2023-10-13 03:54:43 -04:00
|
|
|
ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2));
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->channelBandwidth->setValueRange(true, 8, 0, m_basebandSampleRate);
|
2023-10-13 03:54:43 -04:00
|
|
|
}
|
2023-09-28 11:45:35 -04:00
|
|
|
if (m_channelMarker.getBandwidth() == 0) {
|
|
|
|
m_channelMarker.setBandwidth(m_basebandSampleRate);
|
|
|
|
}
|
|
|
|
updateAbsoluteCenterFrequency();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgReportChannels::match(message))
|
|
|
|
{
|
|
|
|
FreqScanner::MsgReportChannels& report = (FreqScanner::MsgReportChannels&)message;
|
2024-02-16 11:31:12 -05:00
|
|
|
updateChannelsList(report.getChannels(), report.getRenameFrom(), report.getRenameTo());
|
2023-09-28 11:45:35 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgStatus::match(message))
|
|
|
|
{
|
|
|
|
FreqScanner::MsgStatus& report = (FreqScanner::MsgStatus&)message;
|
|
|
|
ui->status->setText(report.getText());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgReportScanning::match(message))
|
|
|
|
{
|
|
|
|
ui->status->setText("Scanning");
|
|
|
|
ui->table->clearSelection();
|
|
|
|
ui->channelPower->setText("-");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgScanComplete::match(message))
|
|
|
|
{
|
|
|
|
ui->startStop->setChecked(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgReportActiveFrequency::match(message))
|
|
|
|
{
|
|
|
|
FreqScanner::MsgReportActiveFrequency& report = (FreqScanner::MsgReportActiveFrequency&)message;
|
|
|
|
qint64 f = report.getCenterFrequency();
|
|
|
|
QString frequency;
|
|
|
|
QString annotation;
|
|
|
|
QList<QTableWidgetItem*> items = ui->table->findItems(QString::number(f), Qt::MatchExactly);
|
|
|
|
if (items.size() > 0)
|
|
|
|
{
|
|
|
|
ui->table->selectRow(items[0]->row());
|
|
|
|
frequency = ui->table->item(items[0]->row(), COL_FREQUENCY)->text();
|
|
|
|
annotation = ui->table->item(items[0]->row(), COL_ANNOTATION)->text();
|
|
|
|
}
|
|
|
|
FrequencyDelegate freqDelegate("Auto", 3);
|
|
|
|
QString formattedFrequency = freqDelegate.displayText(frequency, QLocale::system());
|
|
|
|
ui->status->setText(QString("Active: %1 %2").arg(formattedFrequency).arg(annotation));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgReportActivePower::match(message))
|
|
|
|
{
|
|
|
|
FreqScanner::MsgReportActivePower& report = (FreqScanner::MsgReportActivePower&)message;
|
|
|
|
float power = report.getPower();
|
|
|
|
ui->channelPower->setText(QString::number(power, 'f', 1));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgReportScanRange::match(message))
|
|
|
|
{
|
|
|
|
FreqScanner::MsgReportScanRange& report = (FreqScanner::MsgReportScanRange&)message;
|
|
|
|
m_channelMarker.setCenterFrequency(report.getCenterFrequency());
|
|
|
|
m_channelMarker.setBandwidth(report.getTotalBandwidth());
|
2023-10-03 11:09:54 -04:00
|
|
|
m_channelMarker.setVisible(report.getTotalBandwidth() < m_basebandSampleRate); // Hide marker if full bandwidth
|
2023-09-28 11:45:35 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (FreqScanner::MsgScanResult::match(message))
|
|
|
|
{
|
|
|
|
FreqScanner::MsgScanResult& report = (FreqScanner::MsgScanResult&)message;
|
|
|
|
QList<FreqScanner::MsgScanResult::ScanResult> results = report.getScanResults();
|
|
|
|
|
|
|
|
// Clear column
|
|
|
|
for (int i = 0; i < ui->table->rowCount(); i++)
|
|
|
|
{
|
|
|
|
QTableWidgetItem* item = ui->table->item(i, COL_POWER);
|
|
|
|
item->setText("");
|
|
|
|
item->setBackground(QBrush());
|
|
|
|
}
|
|
|
|
// Add results
|
|
|
|
for (int i = 0; i < results.size(); i++)
|
|
|
|
{
|
|
|
|
qint64 freq = results[i].m_frequency;
|
|
|
|
QList<QTableWidgetItem *> items = ui->table->findItems(QString::number(freq), Qt::MatchExactly);
|
2023-11-29 12:13:34 -05:00
|
|
|
for (auto item : items)
|
|
|
|
{
|
2023-09-28 11:45:35 -04:00
|
|
|
int row = item->row();
|
2023-09-28 14:02:58 -04:00
|
|
|
QTableWidgetItem* powerItem = ui->table->item(row, COL_POWER);
|
|
|
|
powerItem->setData(Qt::DisplayRole, results[i].m_power);
|
2023-11-29 12:13:34 -05:00
|
|
|
FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(freq);
|
|
|
|
Real threshold = m_settings.getThreshold(frequencySettings);
|
|
|
|
bool active = results[i].m_power >= threshold;
|
2023-09-28 11:45:35 -04:00
|
|
|
if (active)
|
|
|
|
{
|
2023-09-28 14:02:58 -04:00
|
|
|
powerItem->setBackground(Qt::darkGreen);
|
2023-09-28 11:45:35 -04:00
|
|
|
QTableWidgetItem* activeCountItem = ui->table->item(row, COL_ACTIVE_COUNT);
|
|
|
|
activeCountItem->setData(Qt::DisplayRole, activeCountItem->data(Qt::DisplayRole).toInt() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-02-16 11:31:12 -05:00
|
|
|
void FreqScannerGUI::updateChannelsCombo(QComboBox *combo, const AvailableChannelOrFeatureList& channels, const QString& channel, bool empty)
|
2023-09-28 11:45:35 -04:00
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
combo->blockSignals(true);
|
|
|
|
combo->clear();
|
|
|
|
if (empty) {
|
|
|
|
combo->addItem("");
|
|
|
|
}
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
for (const auto& channel : channels)
|
|
|
|
{
|
2023-09-29 04:38:15 -04:00
|
|
|
// Add channels in this device set, other than ourself (Don't use ChannelGUI::getDeviceSetIndex()/getIndex() as not valid when this is first called)
|
2024-02-16 11:31:12 -05:00
|
|
|
if ((channel.m_superIndex == m_freqScanner->getDeviceSetIndex()) && (channel.m_index != m_freqScanner->getIndexInDeviceSet())) {
|
|
|
|
combo->addItem(channel.getId());
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Channel can be created after this plugin, so select it
|
|
|
|
// if the chosen channel appears
|
2023-11-29 12:13:34 -05:00
|
|
|
int channelIndex = combo->findText(channel);
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
if (channelIndex >= 0) {
|
2023-11-29 12:13:34 -05:00
|
|
|
combo->setCurrentIndex(channelIndex);
|
2023-09-28 11:45:35 -04:00
|
|
|
} else {
|
2023-11-29 12:13:34 -05:00
|
|
|
combo->setCurrentIndex(-1); // return to nothing selected
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
2023-11-29 12:13:34 -05:00
|
|
|
combo->blockSignals(false);
|
|
|
|
}
|
|
|
|
|
2024-02-16 11:31:12 -05:00
|
|
|
void FreqScannerGUI::updateChannelsList(const AvailableChannelOrFeatureList& channels, const QStringList& renameFrom, const QStringList& renameTo)
|
2023-11-29 12:13:34 -05:00
|
|
|
{
|
2024-02-16 11:31:12 -05:00
|
|
|
m_availableChannels = channels;
|
|
|
|
|
|
|
|
// Update channel setting if it has been renamed
|
|
|
|
if (renameFrom.contains(m_settings.m_channel))
|
|
|
|
{
|
|
|
|
m_settings.m_channel = renameTo[renameFrom.indexOf(m_settings.m_channel)];
|
|
|
|
applySetting("channel");
|
|
|
|
}
|
|
|
|
bool rename = false;
|
|
|
|
for (auto& setting : m_settings.m_frequencySettings)
|
|
|
|
{
|
|
|
|
if (renameFrom.contains(setting.m_channel))
|
|
|
|
{
|
|
|
|
setting.m_channel = renameTo[renameFrom.indexOf(setting.m_channel)];
|
|
|
|
rename = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rename) {
|
|
|
|
applySetting("frequencySettings");
|
|
|
|
}
|
|
|
|
|
2023-11-29 12:13:34 -05:00
|
|
|
updateChannelsCombo(ui->channels, channels, m_settings.m_channel, false);
|
|
|
|
|
|
|
|
for (int row = 0; row < ui->table->rowCount(); row++)
|
|
|
|
{
|
|
|
|
QComboBox *combo = qobject_cast<QComboBox *>(ui->table->cellWidget(row, COL_CHANNEL));
|
|
|
|
updateChannelsCombo(combo, channels, m_settings.m_frequencySettings[row].m_channel, true);
|
|
|
|
}
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_channels_currentIndexChanged(int index)
|
|
|
|
{
|
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
m_settings.m_channel = ui->channels->currentText();
|
|
|
|
applySetting("channel");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::handleInputMessages()
|
|
|
|
{
|
|
|
|
Message* message;
|
|
|
|
|
|
|
|
while ((message = getInputMessageQueue()->pop()) != 0)
|
|
|
|
{
|
|
|
|
if (handleMessage(*message)) {
|
|
|
|
delete message;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::channelMarkerChangedByCursor()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::channelMarkerHighlightedByCursor()
|
|
|
|
{
|
|
|
|
setHighlighted(m_channelMarker.getHighlighted());
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_deltaFrequency_changed(qint64 value)
|
|
|
|
{
|
|
|
|
m_settings.m_channelFrequencyOffset = value;
|
|
|
|
applySetting("channelFrequencyOffset");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_channelBandwidth_changed(qint64 value)
|
|
|
|
{
|
|
|
|
m_settings.m_channelBandwidth = value;
|
|
|
|
applySetting("channelBandwidth");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_scanTime_valueChanged(int value)
|
|
|
|
{
|
|
|
|
ui->scanTimeText->setText(QString("%1 s").arg(value / 10.0, 0, 'f', 1));
|
|
|
|
m_settings.m_scanTime = value / 10.0;
|
|
|
|
applySetting("scanTime");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_retransmitTime_valueChanged(int value)
|
|
|
|
{
|
|
|
|
ui->retransmitTimeText->setText(QString("%1 s").arg(value / 10.0, 0, 'f', 1));
|
|
|
|
m_settings.m_retransmitTime = value / 10.0;
|
|
|
|
applySetting("retransmitTime");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_tuneTime_valueChanged(int value)
|
|
|
|
{
|
|
|
|
ui->tuneTimeText->setText(QString("%1 ms").arg(value));
|
|
|
|
m_settings.m_tuneTime = value;
|
|
|
|
applySetting("tuneTime");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_thresh_valueChanged(int value)
|
|
|
|
{
|
|
|
|
ui->threshText->setText(QString("%1 dB").arg(value / 10.0, 0, 'f', 1));
|
|
|
|
m_settings.m_threshold = value / 10.0;
|
|
|
|
applySetting("threshold");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_priority_currentIndexChanged(int index)
|
|
|
|
{
|
|
|
|
m_settings.m_priority = (FreqScannerSettings::Priority)index;
|
|
|
|
applySetting("priority");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_measurement_currentIndexChanged(int index)
|
|
|
|
{
|
|
|
|
m_settings.m_measurement = (FreqScannerSettings::Measurement)index;
|
|
|
|
applySetting("measurement");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_mode_currentIndexChanged(int index)
|
|
|
|
{
|
|
|
|
m_settings.m_mode = (FreqScannerSettings::Mode)index;
|
|
|
|
applySetting("mode");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|
|
|
{
|
|
|
|
(void) widget;
|
|
|
|
(void) rollDown;
|
|
|
|
|
|
|
|
getRollupContents()->saveState(m_rollupState);
|
|
|
|
applySetting("rollupState");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::onMenuDialogCalled(const QPoint &p)
|
|
|
|
{
|
|
|
|
if (m_contextMenuType == ContextMenuChannelSettings)
|
|
|
|
{
|
|
|
|
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
|
|
|
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
|
|
|
|
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
|
|
|
|
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
|
|
|
|
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
|
|
|
|
dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex);
|
|
|
|
dialog.setDefaultTitle(m_displayedName);
|
|
|
|
|
|
|
|
if (m_deviceUISet->m_deviceMIMOEngine)
|
|
|
|
{
|
|
|
|
dialog.setNumberOfStreams(m_freqScanner->getNumberOfDeviceStreams());
|
|
|
|
dialog.setStreamIndex(m_settings.m_streamIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
dialog.move(p);
|
|
|
|
new DialogPositioner(&dialog, false);
|
|
|
|
dialog.exec();
|
|
|
|
|
|
|
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
|
|
|
m_settings.m_title = m_channelMarker.getTitle();
|
|
|
|
m_settings.m_useReverseAPI = dialog.useReverseAPI();
|
|
|
|
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
|
|
|
|
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
|
|
|
|
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
|
|
|
|
m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex();
|
|
|
|
|
|
|
|
setWindowTitle(m_settings.m_title);
|
|
|
|
setTitle(m_channelMarker.getTitle());
|
|
|
|
setTitleColor(m_settings.m_rgbColor);
|
|
|
|
|
|
|
|
QList<QString> settingsKeys({
|
2023-10-13 03:54:43 -04:00
|
|
|
"rgbColor",
|
2023-09-28 11:45:35 -04:00
|
|
|
"title",
|
|
|
|
"useReverseAPI",
|
|
|
|
"reverseAPIAddress",
|
|
|
|
"reverseAPIPort",
|
|
|
|
"reverseAPIDeviceIndex",
|
|
|
|
"reverseAPIChannelIndex"
|
|
|
|
});
|
|
|
|
|
|
|
|
if (m_deviceUISet->m_deviceMIMOEngine)
|
|
|
|
{
|
|
|
|
m_settings.m_streamIndex = dialog.getSelectedStreamIndex();
|
|
|
|
m_channelMarker.clearStreamIndexes();
|
|
|
|
m_channelMarker.addStreamIndex(m_settings.m_streamIndex);
|
|
|
|
updateIndexLabel();
|
|
|
|
}
|
|
|
|
|
|
|
|
applySettings(settingsKeys);
|
|
|
|
}
|
|
|
|
|
|
|
|
resetContextMenuType();
|
|
|
|
}
|
|
|
|
|
|
|
|
FreqScannerGUI::FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) :
|
|
|
|
ChannelGUI(parent),
|
|
|
|
ui(new Ui::FreqScannerGUI),
|
|
|
|
m_pluginAPI(pluginAPI),
|
|
|
|
m_deviceUISet(deviceUISet),
|
|
|
|
m_channelMarker(this),
|
|
|
|
m_deviceCenterFrequency(0),
|
|
|
|
m_doApplySettings(true)
|
|
|
|
{
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
|
m_helpURL = "plugins/channelrx/freqscanner/readme.md";
|
|
|
|
RollupContents *rollupContents = getRollupContents();
|
|
|
|
ui->setupUi(rollupContents);
|
|
|
|
setSizePolicy(rollupContents->sizePolicy());
|
|
|
|
rollupContents->arrangeRollups();
|
|
|
|
connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
|
|
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
|
|
|
|
|
|
|
m_freqScanner = reinterpret_cast<FreqScanner*>(rxChannel);
|
|
|
|
m_freqScanner->setMessageQueueToGUI(getInputMessageQueue());
|
|
|
|
|
|
|
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
|
|
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->deltaFrequency->setValueRange(true, 8, 0, 9999999);
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
ui->channelBandwidth->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->channelBandwidth->setValueRange(true, 8, 0, 9999999);
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
m_channelMarker.setColor(Qt::yellow);
|
|
|
|
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
|
|
|
|
m_channelMarker.setTitle("Frequency Scanner");
|
|
|
|
m_channelMarker.blockSignals(false);
|
2023-10-03 11:09:54 -04:00
|
|
|
m_channelMarker.setVisible(true);
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
setTitleColor(m_channelMarker.getColor());
|
|
|
|
m_settings.setChannelMarker(&m_channelMarker);
|
|
|
|
m_settings.setRollupState(&m_rollupState);
|
|
|
|
|
|
|
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
|
|
|
|
|
|
|
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
|
|
|
|
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
|
|
|
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
|
|
|
|
|
|
|
// Resize the table using dummy data
|
|
|
|
resizeTable();
|
|
|
|
// Allow user to reorder columns
|
|
|
|
ui->table->horizontalHeader()->setSectionsMovable(true);
|
|
|
|
// Add context menu to allow hiding/showing of columns
|
|
|
|
m_menu = new QMenu(ui->table);
|
|
|
|
for (int i = 0; i < ui->table->horizontalHeader()->count(); i++)
|
|
|
|
{
|
|
|
|
QString text = ui->table->horizontalHeaderItem(i)->text();
|
|
|
|
m_menu->addAction(createCheckableItem(text, i, true));
|
|
|
|
}
|
|
|
|
ui->table->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(ui->table->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(columnSelectMenu(QPoint)));
|
|
|
|
// Get signals when columns change
|
|
|
|
connect(ui->table->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(table_sectionMoved(int, int, int)));
|
|
|
|
connect(ui->table->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(table_sectionResized(int, int, int)));
|
|
|
|
// Context menu
|
|
|
|
ui->table->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(ui->table, &QTableWidget::customContextMenuRequested, this, &FreqScannerGUI::table_customContextMenuRequested);
|
|
|
|
TableTapAndHold* tableTapAndHold = new TableTapAndHold(ui->table);
|
|
|
|
connect(tableTapAndHold, &TableTapAndHold::tapAndHold, this, &FreqScannerGUI::table_customContextMenuRequested);
|
|
|
|
|
|
|
|
ui->startStop->setStyleSheet(QString("QToolButton{ background-color: blue; } QToolButton:checked{ background-color: green; }"));
|
|
|
|
|
|
|
|
displaySettings();
|
|
|
|
makeUIConnections();
|
|
|
|
applyAllSettings();
|
2023-11-13 15:51:03 -05:00
|
|
|
m_resizer.enableChildMouseTracking();
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
ui->table->setItemDelegateForColumn(COL_FREQUENCY, new FrequencyDelegate("Auto", 3));
|
|
|
|
ui->table->setItemDelegateForColumn(COL_POWER, new DecimalDelegate(1));
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->table->setItemDelegateForColumn(COL_CHANNEL_BW, new Int64Delegate(0, 10000000));
|
|
|
|
ui->table->setItemDelegateForColumn(COL_TH, new DecimalDelegate(1, -120.0, 0.0));
|
|
|
|
ui->table->setItemDelegateForColumn(COL_SQ, new DecimalDelegate(1, -120.0, 0.0));
|
2023-10-03 11:09:54 -04:00
|
|
|
|
|
|
|
connect(m_deviceUISet->m_spectrum->getSpectrumView(), &GLSpectrumView::updateAnnotations, this, &FreqScannerGUI::updateAnnotations);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
FreqScannerGUI::~FreqScannerGUI()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::blockApplySettings(bool block)
|
|
|
|
{
|
|
|
|
m_doApplySettings = !block;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::applySetting(const QString& settingsKey)
|
|
|
|
{
|
|
|
|
applySettings({settingsKey});
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::applySettings(const QStringList& settingsKeys, bool force)
|
|
|
|
{
|
2024-02-16 11:31:12 -05:00
|
|
|
m_settingsKeys.append(settingsKeys);
|
2023-09-28 11:45:35 -04:00
|
|
|
if (m_doApplySettings)
|
|
|
|
{
|
2024-02-16 11:31:12 -05:00
|
|
|
FreqScanner::MsgConfigureFreqScanner* message = FreqScanner::MsgConfigureFreqScanner::create(m_settings, m_settingsKeys, force);
|
2023-09-28 11:45:35 -04:00
|
|
|
m_freqScanner->getInputMessageQueue()->push(message);
|
2024-02-16 11:31:12 -05:00
|
|
|
m_settingsKeys.clear();
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::applyAllSettings()
|
|
|
|
{
|
|
|
|
applySettings(QStringList(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::displaySettings()
|
|
|
|
{
|
|
|
|
m_channelMarker.blockSignals(true);
|
|
|
|
m_channelMarker.setBandwidth(m_basebandSampleRate);
|
|
|
|
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
|
|
|
|
m_channelMarker.setTitle(m_settings.m_title);
|
|
|
|
m_channelMarker.blockSignals(false);
|
|
|
|
m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
|
|
|
|
|
|
|
|
setTitleColor(m_settings.m_rgbColor);
|
|
|
|
setWindowTitle(m_channelMarker.getTitle());
|
|
|
|
setTitle(m_channelMarker.getTitle());
|
|
|
|
|
|
|
|
blockApplySettings(true);
|
2023-09-29 09:35:52 -04:00
|
|
|
int channelIndex = ui->channels->findText(m_settings.m_channel);
|
|
|
|
if (channelIndex >= 0) {
|
|
|
|
ui->channels->setCurrentIndex(channelIndex);
|
|
|
|
}
|
2023-09-28 11:45:35 -04:00
|
|
|
ui->deltaFrequency->setValue(m_settings.m_channelFrequencyOffset);
|
|
|
|
ui->channelBandwidth->setValue(m_settings.m_channelBandwidth);
|
|
|
|
ui->scanTime->setValue(m_settings.m_scanTime * 10.0);
|
|
|
|
ui->scanTimeText->setText(QString("%1 s").arg(m_settings.m_scanTime, 0, 'f', 1));
|
|
|
|
ui->retransmitTime->setValue(m_settings.m_retransmitTime * 10.0);
|
|
|
|
ui->retransmitTimeText->setText(QString("%1 s").arg(m_settings.m_retransmitTime, 0, 'f', 1));
|
|
|
|
ui->tuneTime->setValue(m_settings.m_tuneTime);
|
|
|
|
ui->tuneTimeText->setText(QString("%1 ms").arg(m_settings.m_tuneTime));
|
|
|
|
ui->thresh->setValue(m_settings.m_threshold * 10.0);
|
|
|
|
ui->threshText->setText(QString("%1 dB").arg(m_settings.m_threshold, 0, 'f', 1));
|
|
|
|
ui->priority->setCurrentIndex((int)m_settings.m_priority);
|
|
|
|
ui->measurement->setCurrentIndex((int)m_settings.m_measurement);
|
|
|
|
ui->mode->setCurrentIndex((int)m_settings.m_mode);
|
|
|
|
|
2023-09-29 15:58:19 -04:00
|
|
|
ui->table->blockSignals(true);
|
2023-10-02 10:45:17 -04:00
|
|
|
ui->table->setRowCount(0);
|
2023-11-29 12:13:34 -05:00
|
|
|
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
|
2023-09-29 16:18:27 -04:00
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
addRow(m_settings.m_frequencySettings[i]);
|
2023-09-29 16:18:27 -04:00
|
|
|
updateAnnotation(i);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
2023-09-29 15:58:19 -04:00
|
|
|
ui->table->blockSignals(false);
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
// Order and size columns
|
|
|
|
QHeaderView* header = ui->table->horizontalHeader();
|
|
|
|
for (int i = 0; i < m_settings.m_columnSizes.size(); i++)
|
|
|
|
{
|
|
|
|
bool hidden = m_settings.m_columnSizes[i] == 0;
|
|
|
|
header->setSectionHidden(i, hidden);
|
|
|
|
m_menu->actions().at(i)->setChecked(!hidden);
|
|
|
|
if (m_settings.m_columnSizes[i] > 0) {
|
|
|
|
ui->table->setColumnWidth(i, m_settings.m_columnSizes[i]);
|
|
|
|
}
|
|
|
|
header->moveSection(header->visualIndex(i), m_settings.m_columnIndexes[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
updateIndexLabel();
|
|
|
|
|
|
|
|
getRollupContents()->restoreState(m_rollupState);
|
|
|
|
updateAbsoluteCenterFrequency();
|
|
|
|
blockApplySettings(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::leaveEvent(QEvent* event)
|
|
|
|
{
|
|
|
|
m_channelMarker.setHighlighted(false);
|
|
|
|
ChannelGUI::leaveEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::enterEvent(EnterEventType* event)
|
|
|
|
{
|
|
|
|
m_channelMarker.setHighlighted(true);
|
|
|
|
ChannelGUI::enterEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_startStop_clicked(bool checked)
|
|
|
|
{
|
|
|
|
if (checked)
|
|
|
|
{
|
|
|
|
FreqScanner::MsgStartScan* message = FreqScanner::MsgStartScan::create();
|
|
|
|
m_freqScanner->getInputMessageQueue()->push(message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FreqScanner::MsgStopScan* message = FreqScanner::MsgStopScan::create();
|
|
|
|
m_freqScanner->getInputMessageQueue()->push(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-29 12:13:34 -05:00
|
|
|
void FreqScannerGUI::addRow(const FreqScannerSettings::FrequencySettings& frequencySettings)
|
2023-09-28 11:45:35 -04:00
|
|
|
{
|
|
|
|
int row = ui->table->rowCount();
|
|
|
|
ui->table->setRowCount(row + 1);
|
|
|
|
|
|
|
|
// Must create before frequency so updateAnnotation can work
|
|
|
|
QTableWidgetItem* annotationItem = new QTableWidgetItem();
|
|
|
|
annotationItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
|
|
ui->table->setItem(row, COL_ANNOTATION, annotationItem);
|
|
|
|
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->table->setItem(row, COL_FREQUENCY, new QTableWidgetItem(QString("%1").arg(frequencySettings.m_frequency)));
|
2023-09-28 11:45:35 -04:00
|
|
|
|
|
|
|
QTableWidgetItem *enableItem = new QTableWidgetItem();
|
|
|
|
enableItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
2023-11-29 12:13:34 -05:00
|
|
|
enableItem->setCheckState(frequencySettings.m_enabled ? Qt::Checked : Qt::Unchecked);
|
2023-09-28 11:45:35 -04:00
|
|
|
ui->table->setItem(row, COL_ENABLE, enableItem);
|
|
|
|
|
|
|
|
QTableWidgetItem* powerItem = new QTableWidgetItem();
|
|
|
|
powerItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
|
|
ui->table->setItem(row, COL_POWER, powerItem);
|
|
|
|
|
|
|
|
QTableWidgetItem *activeCountItem = new QTableWidgetItem();
|
|
|
|
activeCountItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
|
|
ui->table->setItem(row, COL_ACTIVE_COUNT, activeCountItem);
|
|
|
|
activeCountItem->setData(Qt::DisplayRole, 0);
|
|
|
|
|
2023-11-29 12:13:34 -05:00
|
|
|
QTableWidgetItem* notesItem = new QTableWidgetItem(frequencySettings.m_notes);
|
2023-09-28 11:45:35 -04:00
|
|
|
ui->table->setItem(row, COL_NOTES, notesItem);
|
2023-11-29 12:13:34 -05:00
|
|
|
|
|
|
|
QComboBox *channelComboBox = new QComboBox();
|
|
|
|
updateChannelsCombo(channelComboBox, m_availableChannels, frequencySettings.m_channel, true);
|
|
|
|
ui->table->setCellWidget(row, COL_CHANNEL, channelComboBox);
|
|
|
|
connect(channelComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_table_channel_currentIndexChanged);
|
|
|
|
|
|
|
|
QTableWidgetItem* channelBandwidthItem = new QTableWidgetItem(frequencySettings.m_channelBandwidth);
|
|
|
|
ui->table->setItem(row, COL_CHANNEL_BW, channelBandwidthItem);
|
|
|
|
|
|
|
|
QTableWidgetItem* thresholdItem = new QTableWidgetItem(frequencySettings.m_threshold);
|
|
|
|
ui->table->setItem(row, COL_TH, thresholdItem);
|
|
|
|
|
|
|
|
QTableWidgetItem* squelchItem = new QTableWidgetItem(frequencySettings.m_squelch);
|
|
|
|
ui->table->setItem(row, COL_SQ, squelchItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_table_channel_currentIndexChanged(int index)
|
|
|
|
{
|
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
QComboBox *combo = qobject_cast<QComboBox *>(sender());
|
|
|
|
QModelIndex tableIndex = ui->table->indexAt(combo->pos());
|
|
|
|
on_table_cellChanged(tableIndex.row(), tableIndex.column());
|
|
|
|
}
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_addSingle_clicked()
|
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
FreqScannerSettings::FrequencySettings frequencySettings;
|
|
|
|
frequencySettings.m_frequency = 0;
|
|
|
|
frequencySettings.m_enabled = true;
|
|
|
|
addRow(frequencySettings);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_addRange_clicked()
|
|
|
|
{
|
2023-09-29 03:42:25 -04:00
|
|
|
FreqScannerAddRangeDialog dialog(m_settings.m_channelBandwidth, this);
|
2023-09-28 11:45:35 -04:00
|
|
|
new DialogPositioner(&dialog, false);
|
|
|
|
if (dialog.exec())
|
|
|
|
{
|
2023-09-29 05:52:21 -04:00
|
|
|
blockApplySettings(true);
|
2023-11-29 12:13:34 -05:00
|
|
|
for (const auto f : dialog.m_frequencies)
|
|
|
|
{
|
|
|
|
FreqScannerSettings::FrequencySettings frequencySettings;
|
|
|
|
frequencySettings.m_frequency = f;
|
|
|
|
frequencySettings.m_enabled = true;
|
|
|
|
addRow(frequencySettings);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
2023-09-29 05:52:21 -04:00
|
|
|
blockApplySettings(false);
|
2023-11-29 12:13:34 -05:00
|
|
|
applySetting("frequencySettings");
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_remove_clicked()
|
|
|
|
{
|
|
|
|
QList<QTableWidgetItem*> items = ui->table->selectedItems();
|
|
|
|
|
|
|
|
for (auto item : items)
|
|
|
|
{
|
|
|
|
int row = ui->table->row(item);
|
|
|
|
ui->table->removeRow(row);
|
2023-11-29 12:13:34 -05:00
|
|
|
m_settings.m_frequencySettings.removeAt(row);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
2023-11-29 12:13:34 -05:00
|
|
|
applySetting("frequencySettings");
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
2023-10-02 10:45:17 -04:00
|
|
|
void FreqScannerGUI::on_removeInactive_clicked()
|
|
|
|
{
|
|
|
|
for (int i = ui->table->rowCount() - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (ui->table->item(i, COL_ACTIVE_COUNT)->data(Qt::DisplayRole).toInt() == 0)
|
|
|
|
{
|
|
|
|
ui->table->removeRow(i);
|
2023-11-29 12:13:34 -05:00
|
|
|
m_settings.m_frequencySettings.removeAt(i);
|
2023-10-02 10:45:17 -04:00
|
|
|
}
|
|
|
|
}
|
2023-11-29 12:13:34 -05:00
|
|
|
applySetting("frequencySettings");
|
2023-10-02 10:45:17 -04:00
|
|
|
}
|
|
|
|
|
2023-09-28 11:45:35 -04:00
|
|
|
static QList<QTableWidgetItem*> takeRow(QTableWidget* table, int row)
|
|
|
|
{
|
|
|
|
QList<QTableWidgetItem*> rowItems;
|
|
|
|
|
|
|
|
for (int col = 0; col < table->columnCount(); col++) {
|
|
|
|
rowItems.append(table->takeItem(row, col));
|
|
|
|
}
|
|
|
|
return rowItems;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setRow(QTableWidget* table, int row, const QList<QTableWidgetItem*>& rowItems)
|
|
|
|
{
|
|
|
|
for (int col = 0; col < rowItems.size(); col++) {
|
|
|
|
table->setItem(row, col, rowItems.at(col));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_up_clicked()
|
|
|
|
{
|
|
|
|
QList<QTableWidgetItem*> items = ui->table->selectedItems();
|
|
|
|
for (auto item : items)
|
|
|
|
{
|
|
|
|
int row = ui->table->row(item);
|
|
|
|
if (row > 0)
|
|
|
|
{
|
|
|
|
QList<QTableWidgetItem*> sourceItems = takeRow(ui->table, row);
|
|
|
|
QList<QTableWidgetItem*> destItems = takeRow(ui->table, row - 1);
|
|
|
|
setRow(ui->table, row - 1, sourceItems);
|
|
|
|
setRow(ui->table, row, destItems);
|
|
|
|
ui->table->setCurrentCell(row - 1, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::on_down_clicked()
|
|
|
|
{
|
|
|
|
QList<QTableWidgetItem*> items = ui->table->selectedItems();
|
|
|
|
for (auto item : items)
|
|
|
|
{
|
|
|
|
int row = ui->table->row(item);
|
|
|
|
if (row < ui->table->rowCount() - 1)
|
|
|
|
{
|
|
|
|
QList<QTableWidgetItem*> sourceItems = takeRow(ui->table, row);
|
|
|
|
QList<QTableWidgetItem*> destItems = takeRow(ui->table, row + 1);
|
|
|
|
setRow(ui->table, row + 1, sourceItems);
|
|
|
|
setRow(ui->table, row, destItems);
|
|
|
|
ui->table->setCurrentCell(row + 1, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-29 09:35:52 -04:00
|
|
|
void FreqScannerGUI::on_clearActiveCount_clicked()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ui->table->rowCount(); i++) {
|
|
|
|
ui->table->item(i, COL_ACTIVE_COUNT)->setData(Qt::DisplayRole, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-28 11:45:35 -04:00
|
|
|
void FreqScannerGUI::on_table_cellChanged(int row, int column)
|
|
|
|
{
|
|
|
|
QTableWidgetItem* item = ui->table->item(row, column);
|
|
|
|
if (item)
|
|
|
|
{
|
|
|
|
if (column == COL_FREQUENCY)
|
|
|
|
{
|
|
|
|
qint64 value = item->text().toLongLong();
|
2023-11-29 12:13:34 -05:00
|
|
|
while (m_settings.m_frequencySettings.size() <= row)
|
2023-09-28 11:45:35 -04:00
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
FreqScannerSettings::FrequencySettings frequencySettings;
|
|
|
|
frequencySettings.m_frequency = 0;
|
|
|
|
frequencySettings.m_enabled = true;
|
|
|
|
m_settings.m_frequencySettings.append(frequencySettings);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
2023-11-29 12:13:34 -05:00
|
|
|
m_settings.m_frequencySettings[row].m_frequency = value;
|
2023-09-28 11:45:35 -04:00
|
|
|
updateAnnotation(row);
|
2023-11-29 12:13:34 -05:00
|
|
|
applySetting("frequencySettings");
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
else if (column == COL_ENABLE)
|
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
m_settings.m_frequencySettings[row].m_enabled = item->checkState() == Qt::Checked;
|
|
|
|
applySetting("frequencySettings");
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
else if (column == COL_NOTES)
|
|
|
|
{
|
2023-11-29 12:13:34 -05:00
|
|
|
m_settings.m_frequencySettings[row].m_notes = item->text();
|
|
|
|
applySetting("frequencySettings");
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
2023-11-29 12:13:34 -05:00
|
|
|
else if (column == COL_CHANNEL_BW)
|
|
|
|
{
|
|
|
|
m_settings.m_frequencySettings[row].m_channelBandwidth = item->text();
|
|
|
|
applySetting("frequencySettings");
|
|
|
|
}
|
|
|
|
else if (column == COL_TH)
|
|
|
|
{
|
|
|
|
m_settings.m_frequencySettings[row].m_threshold = item->text();
|
|
|
|
applySetting("frequencySettings");
|
|
|
|
}
|
|
|
|
else if (column == COL_SQ)
|
|
|
|
{
|
|
|
|
m_settings.m_frequencySettings[row].m_squelch = item->text();
|
|
|
|
applySetting("frequencySettings");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (column == COL_CHANNEL)
|
|
|
|
{
|
|
|
|
QComboBox *combo = qobject_cast<QComboBox *>(ui->table->cellWidget(row, COL_CHANNEL));
|
|
|
|
m_settings.m_frequencySettings[row].m_channel = combo->currentText();
|
|
|
|
qDebug() << "Setting row" << row << "to" << combo->currentText();
|
|
|
|
applySetting("frequencySettings");
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::updateAnnotation(int row)
|
|
|
|
{
|
|
|
|
QTableWidgetItem* item = ui->table->item(row, COL_FREQUENCY);
|
|
|
|
QTableWidgetItem* annotationItem = ui->table->item(row, COL_ANNOTATION);
|
|
|
|
if (item && annotationItem)
|
|
|
|
{
|
|
|
|
qint64 frequency = item->text().toLongLong();
|
|
|
|
const QList<SpectrumAnnotationMarker>& markers = m_deviceUISet->m_spectrum->getAnnotationMarkers();
|
|
|
|
const SpectrumAnnotationMarker* closest = nullptr;
|
|
|
|
for (const auto& marker : markers)
|
|
|
|
{
|
2023-10-22 05:01:29 -04:00
|
|
|
qint64 start1 = marker.m_startFrequency;
|
|
|
|
qint64 stop1 = marker.m_startFrequency + marker.m_bandwidth;
|
|
|
|
qint64 start2 = frequency - m_settings.m_channelBandwidth / 2;
|
|
|
|
qint64 stop2 = frequency + m_settings.m_channelBandwidth / 2;
|
|
|
|
if ( ((start2 >= start1) && (start2 <= stop1))
|
|
|
|
|| ((stop2 >= start1) && (stop2 <= stop1))
|
|
|
|
)
|
2023-09-28 11:45:35 -04:00
|
|
|
{
|
2023-09-28 14:02:58 -04:00
|
|
|
if (marker.m_bandwidth == (unsigned)m_settings.m_channelBandwidth) {
|
2023-09-28 11:45:35 -04:00
|
|
|
// Exact match
|
|
|
|
annotationItem->setText(marker.m_text);
|
|
|
|
return;
|
2023-10-03 11:09:54 -04:00
|
|
|
}
|
|
|
|
else if (!closest)
|
|
|
|
{
|
2023-09-28 11:45:35 -04:00
|
|
|
closest = ▮
|
2023-10-03 11:09:54 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-09-28 11:45:35 -04:00
|
|
|
if (marker.m_bandwidth < closest->m_bandwidth) {
|
|
|
|
closest = ▮
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (closest) {
|
|
|
|
annotationItem->setText(closest->m_text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-03 11:09:54 -04:00
|
|
|
void FreqScannerGUI::updateAnnotations()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ui->table->rowCount(); i++) {
|
|
|
|
updateAnnotation(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-22 05:01:29 -04:00
|
|
|
void FreqScannerGUI::setAllEnabled(bool enable)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ui->table->rowCount(); i++) {
|
|
|
|
ui->table->item(i, COL_ENABLE)->setCheckState(enable ? Qt::Checked : Qt::Unchecked);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-28 11:45:35 -04:00
|
|
|
void FreqScannerGUI::table_customContextMenuRequested(QPoint pos)
|
|
|
|
{
|
|
|
|
QTableWidgetItem* item = ui->table->itemAt(pos);
|
|
|
|
if (item)
|
|
|
|
{
|
|
|
|
int row = item->row();
|
|
|
|
|
|
|
|
QMenu* tableContextMenu = new QMenu(ui->table);
|
|
|
|
connect(tableContextMenu, &QMenu::aboutToHide, tableContextMenu, &QMenu::deleteLater);
|
|
|
|
|
|
|
|
// Copy current cell
|
|
|
|
|
|
|
|
QAction* copyAction = new QAction("Copy", tableContextMenu);
|
|
|
|
const QString text = item->text();
|
|
|
|
connect(copyAction, &QAction::triggered, this, [text]()->void {
|
|
|
|
QClipboard* clipboard = QGuiApplication::clipboard();
|
|
|
|
clipboard->setText(text);
|
|
|
|
});
|
|
|
|
tableContextMenu->addAction(copyAction);
|
|
|
|
|
2023-10-22 05:01:29 -04:00
|
|
|
tableContextMenu->addSeparator();
|
|
|
|
|
|
|
|
// Enable all
|
|
|
|
|
|
|
|
QAction* enableAllAction = new QAction("Enable all", tableContextMenu);
|
|
|
|
connect(enableAllAction, &QAction::triggered, this, [this]()->void {
|
|
|
|
setAllEnabled(true);
|
|
|
|
});
|
|
|
|
tableContextMenu->addAction(enableAllAction);
|
|
|
|
|
|
|
|
// Disable all
|
|
|
|
|
|
|
|
QAction* disableAllAction = new QAction("Disable all", tableContextMenu);
|
|
|
|
connect(disableAllAction, &QAction::triggered, this, [this]()->void {
|
|
|
|
setAllEnabled(false);
|
|
|
|
});
|
|
|
|
tableContextMenu->addAction(disableAllAction);
|
|
|
|
|
2023-10-02 10:45:17 -04:00
|
|
|
// Remove selected rows
|
|
|
|
|
|
|
|
QAction* removeAction = new QAction("Remove", tableContextMenu);
|
|
|
|
connect(removeAction, &QAction::triggered, this, [this]()->void {
|
|
|
|
on_remove_clicked();
|
|
|
|
});
|
|
|
|
tableContextMenu->addAction(removeAction);
|
|
|
|
|
2023-09-28 11:45:35 -04:00
|
|
|
tableContextMenu->addSeparator();
|
|
|
|
|
|
|
|
// Tune to frequency
|
|
|
|
|
2023-12-01 07:47:50 -05:00
|
|
|
qint64 frequency = ui->table->item(row, COL_FREQUENCY)->text().toLongLong();
|
|
|
|
FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(frequency);
|
|
|
|
QString channel = m_settings.getChannel(frequencySettings);
|
2023-12-05 07:32:53 -05:00
|
|
|
unsigned int scanDeviceSetIndex, scanChannelIndex;
|
2023-09-28 11:45:35 -04:00
|
|
|
|
2023-12-05 07:32:53 -05:00
|
|
|
if (MainCore::getDeviceAndChannelIndexFromId(channel, scanDeviceSetIndex, scanChannelIndex))
|
|
|
|
{
|
2023-12-01 07:47:50 -05:00
|
|
|
ButtonSwitch *startStop = ui->startStop;
|
2023-09-28 11:45:35 -04:00
|
|
|
|
2023-12-05 07:32:53 -05:00
|
|
|
QAction* findChannelMapAction = new QAction(QString("Tune %1 to %2").arg(channel).arg(frequency), tableContextMenu);
|
2023-12-01 07:47:50 -05:00
|
|
|
connect(findChannelMapAction, &QAction::triggered, this, [this, scanDeviceSetIndex, scanChannelIndex, frequency, startStop]()->void {
|
2023-09-28 11:45:35 -04:00
|
|
|
|
2023-12-01 07:47:50 -05:00
|
|
|
// Stop scanning
|
|
|
|
if (startStop->isChecked()) {
|
|
|
|
startStop->click();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mute all channels
|
|
|
|
m_freqScanner->muteAll(m_settings);
|
|
|
|
|
|
|
|
// Tune to frequency
|
2023-09-28 11:45:35 -04:00
|
|
|
if ((frequency - m_settings.m_channelBandwidth / 2 < m_deviceCenterFrequency - m_basebandSampleRate / 2)
|
|
|
|
|| (frequency + m_settings.m_channelBandwidth / 2 >= m_deviceCenterFrequency + m_basebandSampleRate / 2))
|
|
|
|
{
|
|
|
|
qint64 centerFrequency = frequency;
|
|
|
|
int offset = 0;
|
|
|
|
while (frequency - centerFrequency < m_settings.m_channelFrequencyOffset)
|
|
|
|
{
|
|
|
|
centerFrequency -= m_settings.m_channelBandwidth;
|
|
|
|
offset += m_settings.m_channelBandwidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ChannelWebAPIUtils::setCenterFrequency(getDeviceSetIndex(), centerFrequency)) {
|
|
|
|
qWarning() << "Scanner failed to set frequency" << centerFrequency;
|
|
|
|
}
|
|
|
|
ChannelWebAPIUtils::setFrequencyOffset(scanDeviceSetIndex, scanChannelIndex, offset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int offset = frequency - m_deviceCenterFrequency;
|
|
|
|
ChannelWebAPIUtils::setFrequencyOffset(scanDeviceSetIndex, scanChannelIndex, offset);
|
|
|
|
}
|
|
|
|
|
2023-12-01 07:47:50 -05:00
|
|
|
// Unmute channel
|
|
|
|
ChannelWebAPIUtils::setAudioMute(scanDeviceSetIndex, scanChannelIndex, false);
|
|
|
|
|
2023-09-28 11:45:35 -04:00
|
|
|
});
|
|
|
|
tableContextMenu->addAction(findChannelMapAction);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
qDebug() << "Failed to parse channel" << m_settings.m_channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
tableContextMenu->popup(ui->table->viewport()->mapToGlobal(pos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Columns in table reordered
|
|
|
|
void FreqScannerGUI::table_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
|
|
|
|
{
|
|
|
|
(void)oldVisualIndex;
|
|
|
|
m_settings.m_columnIndexes[logicalIndex] = newVisualIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Column in table resized (when hidden size is 0)
|
|
|
|
void FreqScannerGUI::table_sectionResized(int logicalIndex, int oldSize, int newSize)
|
|
|
|
{
|
|
|
|
(void)oldSize;
|
|
|
|
m_settings.m_columnSizes[logicalIndex] = newSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Right click in ADSB table header - show column select menu
|
|
|
|
void FreqScannerGUI::columnSelectMenu(QPoint pos)
|
|
|
|
{
|
|
|
|
m_menu->popup(ui->table->horizontalHeader()->viewport()->mapToGlobal(pos));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hide/show column when menu selected
|
|
|
|
void FreqScannerGUI::columnSelectMenuChecked(bool checked)
|
|
|
|
{
|
|
|
|
(void)checked;
|
|
|
|
QAction* action = qobject_cast<QAction*>(sender());
|
|
|
|
if (action != nullptr)
|
|
|
|
{
|
|
|
|
int idx = action->data().toInt(nullptr);
|
|
|
|
ui->table->setColumnHidden(idx, !action->isChecked());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create column select menu item
|
|
|
|
QAction* FreqScannerGUI::createCheckableItem(QString& text, int idx, bool checked)
|
|
|
|
{
|
|
|
|
QAction* action = new QAction(text, this);
|
|
|
|
action->setCheckable(true);
|
|
|
|
action->setChecked(checked);
|
|
|
|
action->setData(QVariant(idx));
|
|
|
|
connect(action, SIGNAL(triggered()), this, SLOT(columnSelectMenuChecked()));
|
|
|
|
return action;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::resizeTable()
|
|
|
|
{
|
|
|
|
// Fill table with a row of dummy data that will size the columns nicely
|
|
|
|
int row = ui->table->rowCount();
|
|
|
|
ui->table->setRowCount(row + 1);
|
2023-10-02 10:45:17 -04:00
|
|
|
ui->table->setItem(row, COL_FREQUENCY, new QTableWidgetItem("800,000.5 MHz"));
|
2023-10-03 11:09:54 -04:00
|
|
|
ui->table->setItem(row, COL_ANNOTATION, new QTableWidgetItem("London VOLMET"));
|
2023-09-28 11:45:35 -04:00
|
|
|
ui->table->setItem(row, COL_ENABLE, new QTableWidgetItem("Enable"));
|
|
|
|
ui->table->setItem(row, COL_POWER, new QTableWidgetItem("-100.0"));
|
|
|
|
ui->table->setItem(row, COL_ACTIVE_COUNT, new QTableWidgetItem("10000"));
|
2023-11-29 12:13:34 -05:00
|
|
|
ui->table->setItem(row, COL_NOTES, new QTableWidgetItem("A channel name"));
|
|
|
|
ui->table->setItem(row, COL_CHANNEL, new QTableWidgetItem("Enter some notes"));
|
|
|
|
ui->table->setItem(row, COL_CHANNEL_BW, new QTableWidgetItem("100000000"));
|
|
|
|
ui->table->setItem(row, COL_TH, new QTableWidgetItem("-100.0"));
|
|
|
|
ui->table->setItem(row, COL_SQ, new QTableWidgetItem("-100.0"));
|
2023-09-28 11:45:35 -04:00
|
|
|
ui->table->resizeColumnsToContents();
|
|
|
|
ui->table->setRowCount(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::makeUIConnections()
|
|
|
|
{
|
|
|
|
QObject::connect(ui->channels, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_channels_currentIndexChanged);
|
|
|
|
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &FreqScannerGUI::on_deltaFrequency_changed);
|
|
|
|
QObject::connect(ui->channelBandwidth, &ValueDialZ::changed, this, &FreqScannerGUI::on_channelBandwidth_changed);
|
|
|
|
QObject::connect(ui->scanTime, &QDial::valueChanged, this, &FreqScannerGUI::on_scanTime_valueChanged);
|
|
|
|
QObject::connect(ui->retransmitTime, &QDial::valueChanged, this, &FreqScannerGUI::on_retransmitTime_valueChanged);
|
|
|
|
QObject::connect(ui->tuneTime, &QDial::valueChanged, this, &FreqScannerGUI::on_tuneTime_valueChanged);
|
|
|
|
QObject::connect(ui->thresh, &QDial::valueChanged, this, &FreqScannerGUI::on_thresh_valueChanged);
|
|
|
|
QObject::connect(ui->priority, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_priority_currentIndexChanged);
|
|
|
|
QObject::connect(ui->measurement, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_measurement_currentIndexChanged);
|
|
|
|
QObject::connect(ui->mode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_mode_currentIndexChanged);
|
|
|
|
QObject::connect(ui->startStop, &ButtonSwitch::clicked, this, &FreqScannerGUI::on_startStop_clicked);
|
|
|
|
QObject::connect(ui->table, &QTableWidget::cellChanged, this, &FreqScannerGUI::on_table_cellChanged);
|
|
|
|
QObject::connect(ui->addSingle, &QToolButton::clicked, this, &FreqScannerGUI::on_addSingle_clicked);
|
|
|
|
QObject::connect(ui->addRange, &QToolButton::clicked, this, &FreqScannerGUI::on_addRange_clicked);
|
|
|
|
QObject::connect(ui->remove, &QToolButton::clicked, this, &FreqScannerGUI::on_remove_clicked);
|
2023-10-02 10:45:17 -04:00
|
|
|
QObject::connect(ui->removeInactive, &QToolButton::clicked, this, &FreqScannerGUI::on_removeInactive_clicked);
|
2023-09-28 11:45:35 -04:00
|
|
|
QObject::connect(ui->up, &QToolButton::clicked, this, &FreqScannerGUI::on_up_clicked);
|
|
|
|
QObject::connect(ui->down, &QToolButton::clicked, this, &FreqScannerGUI::on_down_clicked);
|
2023-09-29 09:35:52 -04:00
|
|
|
QObject::connect(ui->clearActiveCount, &QToolButton::clicked, this, &FreqScannerGUI::on_clearActiveCount_clicked);
|
2023-09-28 11:45:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void FreqScannerGUI::updateAbsoluteCenterFrequency()
|
|
|
|
{
|
|
|
|
setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset);
|
|
|
|
}
|