Files
Artemis/main.py
2018-11-11 17:55:14 +01:00

861 lines
37 KiB
Python

from collections import namedtuple
from functools import partial
import webbrowser
import os
import sys
from pandas import read_csv
from PyQt5.QtWidgets import (QMainWindow,
QApplication,
QMessageBox,
qApp,
QDesktopWidget,
QListWidgetItem,
QTreeView,
QTreeWidgetItem)
from PyQt5.QtGui import QPixmap, QStandardItemModel, QStandardItem
from PyQt5 import uic
from PyQt5.QtCore import (QFileInfo,
QSize,
Qt,
pyqtSlot,)
from audio_player import AudioPlayer
from double_text_button import DoubleTextButton
from download_window import DownloadWindow
from utilities import Constants, reset_apply_remove_btn
qt_creator_file = "main_window.ui"
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
class MyApp(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.set_initial_size()
self.download_window = DownloadWindow()
self.actionExit.triggered.connect(qApp.quit)
self.action_update_database.triggered.connect(self.download_db)
self.db = None
self.current_signal_name = ''
self.signal_names = []
self.total_signals = 0
# Manage frequency filters.
self.frequency_filters_btns = (
self.elf_filter_btn,
self.slf_filter_btn,
self.ulf_filter_btn,
self.vlf_filter_btn,
self.lf_filter_btn,
self.mf_filter_btn,
self.hf_filter_btn,
self.vhf_filter_btn,
self.uhf_filter_btn,
self.shf_filter_btn,
self.ehf_filter_btn,
)
self.connect_to(
objects_to_connect = [self.lower_freq_spinbox.valueChanged,
self.upper_freq_spinbox.valueChanged,
self.lower_freq_filter_unit.currentTextChanged,
self.upper_freq_filter_unit.currentTextChanged,
self.activate_low_freq_filter_btn.toggled],
fun_to_connect = self.set_min_value_upper_limit,
fun_args = [self.lower_freq_filter_unit,
self.lower_freq_spinbox,
self.upper_freq_filter_unit,
self.upper_freq_spinbox]
)
self.connect_to(
objects_to_connect = [self.lower_freq_spinbox.valueChanged,
self.upper_freq_spinbox.valueChanged,
self.lower_freq_filter_unit.currentTextChanged,
self.upper_freq_filter_unit.currentTextChanged,
self.activate_low_freq_filter_btn.clicked,
self.activate_up_freq_filter_btn.clicked,
self.lower_freq_confidence.valueChanged,
self.upper_freq_confidence.valueChanged],
fun_to_connect = self.set_band_filter_label,
fun_args = [self.activate_low_freq_filter_btn,
self.lower_freq_spinbox,
self.lower_freq_filter_unit,
self.lower_freq_confidence,
self.activate_up_freq_filter_btn,
self.upper_freq_spinbox,
self.upper_freq_filter_unit,
self.upper_freq_confidence,
self.freq_range_lbl]
)
self.activate_low_freq_filter_btn.toggled.connect(
partial(self.activate_if_toggled,
self.activate_low_freq_filter_btn,
self.lower_freq_spinbox,
self.lower_freq_filter_unit,
self.lower_freq_confidence)
)
self.activate_up_freq_filter_btn.toggled.connect(
partial(self.activate_if_toggled,
self.activate_up_freq_filter_btn,
self.upper_freq_spinbox,
self.upper_freq_filter_unit,
self.upper_freq_confidence)
)
self.apply_remove_freq_filter_btn.set_texts("Apply", "Remove")
self.apply_remove_freq_filter_btn.set_slave_filters(
[
*self.frequency_filters_btns,
self.include_undef_freqs,
self.activate_low_freq_filter_btn,
self.activate_up_freq_filter_btn,
],
self.activate_low_freq_filter_btn,
[
self.lower_freq_spinbox,
self.lower_freq_filter_unit,
self.lower_freq_confidence,
],
self.activate_up_freq_filter_btn,
[
self.upper_freq_spinbox,
self.upper_freq_filter_unit,
self.upper_freq_confidence,
],
)
self.apply_remove_freq_filter_btn.clicked.connect(self.display_signals)
self.reset_frequency_filters_btn.clicked.connect(partial(self.reset_fb_filters, 'freq'))
# Manage bandwidth filters.
self.connect_to(
objects_to_connect = [self.lower_band_spinbox.valueChanged,
self.upper_band_spinbox.valueChanged,
self.lower_band_filter_unit.currentTextChanged,
self.upper_band_filter_unit.currentTextChanged,
self.activate_low_band_filter_btn.toggled],
fun_to_connect = self.set_min_value_upper_limit,
fun_args = [self.lower_band_filter_unit,
self.lower_band_spinbox,
self.upper_band_filter_unit,
self.upper_band_spinbox]
)
self.connect_to(
objects_to_connect = [self.lower_band_spinbox.valueChanged,
self.upper_band_spinbox.valueChanged,
self.lower_band_filter_unit.currentTextChanged,
self.upper_band_filter_unit.currentTextChanged,
self.activate_low_band_filter_btn.clicked,
self.activate_up_band_filter_btn.clicked,
self.lower_band_confidence.valueChanged,
self.upper_band_confidence.valueChanged],
fun_to_connect = self.set_band_filter_label,
fun_args = [self.activate_low_band_filter_btn,
self.lower_band_spinbox,
self.lower_band_filter_unit,
self.lower_band_confidence,
self.activate_up_band_filter_btn,
self.upper_band_spinbox,
self.upper_band_filter_unit,
self.upper_band_confidence,
self.band_range_lbl]
)
self.activate_low_band_filter_btn.toggled.connect(
partial(self.activate_if_toggled,
self.activate_low_band_filter_btn,
self.lower_band_spinbox,
self.lower_band_filter_unit,
self.lower_band_confidence)
)
self.activate_up_band_filter_btn.toggled.connect(
partial(self.activate_if_toggled,
self.activate_up_band_filter_btn,
self.upper_band_spinbox,
self.upper_band_filter_unit,
self.upper_band_confidence)
)
self.apply_remove_band_filter_btn.set_texts("Apply", "Remove")
self.apply_remove_band_filter_btn.set_slave_filters(
[
self.include_undef_bands,
self.activate_low_band_filter_btn,
self.activate_up_band_filter_btn,
],
self.activate_low_band_filter_btn,
[
self.lower_band_spinbox,
self.lower_band_filter_unit,
self.lower_band_confidence,
],
self.activate_up_band_filter_btn,
[
self.upper_band_spinbox,
self.upper_band_filter_unit,
self.upper_band_confidence,
],
)
self.apply_remove_band_filter_btn.clicked.connect(self.display_signals)
self.reset_band_filters_btn.clicked.connect(partial(self.reset_fb_filters, 'band'))
# Manage category filters
# Order matters!
self.cat_filter_btns = [self.military_btn,
self.radar_btn,
self.active_btn,
self.inactive_btn,
self.ham_btn,
self.commercial_btn,
self.aviation_btn,
self.marine_btn,
self.analogue_btn,
self.digital_btn,
self.trunked_btn,
self.utility_btn,
self.sat_btn,
self.navigation_btn,
self.interfering_btn,
self.number_stations_btn,
self.time_signal_btn,]
self.apply_remove_cat_filter_btn.set_texts('Apply', 'Remove')
self.apply_remove_cat_filter_btn.set_slave_filters([*self.cat_filter_btns,
self.cat_at_least_one,
self.cat_all])
self.apply_remove_cat_filter_btn.clicked.connect(self.display_signals)
self.reset_cat_filters_btn.clicked.connect(self.reset_cat_filters)
# #######################################################################################
self.reset_filters_btn.clicked.connect(self.reset_all_filters)
UrlColors = namedtuple("UrlColors", ["inactive", "active", "clicked"])
self.url_button.colors = UrlColors("#9f9f9f", "#4c75ff", "#942ccc")
self.category_labels = [self.cat_mil,
self.cat_rad,
self.cat_active,
self.cat_inactive,
self.cat_ham,
self.cat_comm,
self.cat_avi,
self.cat_mar,
self.cat_ana,
self.cat_dig,
self.cat_trunked,
self.cat_utility,
self.cat_sat,
self.cat_navi,
self.cat_interf,
self.cat_num_stat,
self.cat_time_sig,]
self.property_labels = [self.freq_lab,
self.band_lab,
self.mode_lab,
self.modul_lab,
self.loc_lab,
self.acf_lab,
self.description_text,]
self.url_button.clicked.connect(self.go_to_web_page_signal)
# Set mode TreeView
self.set_mode_tree_widget()
self.mode_tree_widget.itemSelectionChanged.connect(self.manage_mode_selections)
self.reset_mode_filters_btn.clicked.connect(self.reset_mode_filters)
self.apply_remove_mode_filter_btn.set_texts("Apply", "Remove")
self.apply_remove_mode_filter_btn.set_slave_filters([self.mode_tree_widget,
self.include_unknown_modes_btn])
self.apply_remove_mode_filter_btn.clicked.connect(self.display_signals)
# Set modulation filter screen.
self.modulation_list.addItems(Constants.MODULATIONS)
# ##########################################################################################
self.show()
self.load_db()
self.display_signals()
self.search_bar.textChanged.connect(self.display_signals)
self.result_list.currentItemChanged.connect(self.display_specs)
self.result_list.itemDoubleClicked.connect(lambda: self.main_tab.setCurrentWidget(
self.signal_properties_tab
)
)
self.audio_widget = AudioPlayer(self.play,
self.pause,
self.stop,
self.volume,
self.audio_progress)
BandLabel = namedtuple("BandLabel", ["left", "center", "right"])
self.band_labels = [
BandLabel(self.elf_left, self.elf, self.elf_right),
BandLabel(self.slf_left, self.slf, self.slf_right),
BandLabel(self.ulf_left, self.ulf, self.ulf_right),
BandLabel(self.vlf_left, self.vlf, self.vlf_right),
BandLabel(self.lf_left, self.lf, self.lf_right),
BandLabel(self.mf_left, self.mf, self.mf_right),
BandLabel(self.hf_left, self.hf, self.hf_right),
BandLabel(self.vhf_left, self.vhf, self.vhf_right),
BandLabel(self.uhf_left, self.uhf, self.uhf_right),
BandLabel(self.shf_left, self.shf, self.shf_right),
BandLabel(self.ehf_left, self.ehf, self.ehf_right),
]
def set_mode_tree_widget(self):
for parent, children in Constants.MODES.items():
iparent = QTreeWidgetItem([parent])
self.mode_tree_widget.addTopLevelItem(iparent)
for child in children:
ichild = QTreeWidgetItem([child])
iparent.addChild(ichild)
self.mode_tree_widget.expandAll()
def manage_mode_selections(self):
selected_items = self.mode_tree_widget.selectedItems()
parents = Constants.MODES.keys()
for parent in parents:
for item in selected_items:
if parent == item.text(0):
for i in range(len(Constants.MODES[parent])):
item.child(i).setSelected(True)
def set_initial_size(self):
"""
Function to handle high resolution screens. The function sets bigger sizes
for all the relevant fixed-size widgets.
"""
d = QDesktopWidget().availableGeometry()
w = d.width()
h = d.height()
self.setGeometry(50, 50, (3 * w) // 4, (3 * h) // 4)
if w > 3000 or h > 2000:
self.fixed_audio_and_image.setFixedSize(540, 1150)
self.fixed_audio_and_image.setMaximumSize(540, 1150)
self.play.setFixedSize(140, 140)
self.pause.setFixedSize(140, 140)
self.stop.setFixedSize(140, 140)
self.lower_freq_spinbox.setFixedWidth(200)
self.upper_freq_spinbox.setFixedWidth(200)
self.lower_freq_filter_unit.setFixedWidth(120)
self.upper_freq_filter_unit.setFixedWidth(120)
self.lower_freq_confidence.setFixedWidth(120)
self.upper_freq_confidence.setFixedWidth(120)
self.lower_band_spinbox.setFixedWidth(200)
self.upper_band_spinbox.setFixedWidth(200)
self.lower_band_filter_unit.setFixedWidth(120)
self.upper_band_filter_unit.setFixedWidth(120)
self.lower_band_confidence.setFixedWidth(120)
self.upper_band_confidence.setFixedWidth(120)
self.audio_progress.setFixedHeight(20)
self.volume.setStyleSheet("""
QSlider::groove:horizontal {
height: 12px;
background: #7a7a7a;
margin: 0 10px;
border-radius: 6px
}
QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 gray, stop:0.5 white, stop:1.0 gray);
border: 1px solid #5c5c5c;
width: 28px;
margin: -8px -8px;
border-radius: 14px;
}
""")
@pyqtSlot()
def download_db(self):
self.download_window.download_thread.finished.connect(self.show_downloaded_signals)
self.download_window.download_thread.start()
self.download_window.show()
@pyqtSlot()
def show_downloaded_signals(self):
if self.download_window.everything_ok:
self.search_bar.setEnabled(True)
self.load_db()
self.display_signals()
def load_db(self):
names = ["name",
"inf_freq",
"sup_freq",
"mode",
"inf_band",
"sup_band",
"location",
"url",
"description",
"modulation",
"category_code",
"acf",]
try:
self.db = read_csv(os.path.join(Constants.DATA_FOLDER, 'db.csv'),
sep = '*',
header = None,
index_col = 0,
dtype = {'inf_freq': str,
'sup_freq': str,
'mode': str,
'inf_band': str,
'sup_band': str,
'category_code': str,},
names = names,)
except FileNotFoundError:
self.search_bar.setDisabled(True)
box = QMessageBox(self)
box.setWindowTitle("No database")
box.setText("No database available.\n"
"Go to Updates->Update database.")
box.show()
else:
self.signal_names = self.db.index
self.total_signals = len(self.signal_names)
self.db.fillna("N/A", inplace = True)
self.db["url_clicked"] = False
self.update_status_tip(self.total_signals)
@staticmethod
def connect_to(objects_to_connect, fun_to_connect, fun_args):
for signal in objects_to_connect:
signal.connect(partial(fun_to_connect, *fun_args))
@pyqtSlot()
def set_min_value_upper_limit(self, lower_combo_box,
lower_spin_box,
upper_combo_box,
upper_spin_box):
if lower_spin_box.isEnabled():
unit_conversion = {'Hz' : ['kHz', 'MHz', 'GHz'],
'kHz': ['MHz', 'GHz'],
'MHz': ['GHz']
}
lower_units = lower_combo_box.currentText()
upper_units = upper_combo_box.currentText()
lower_value = lower_spin_box.value()
upper_value = upper_spin_box.value()
inf_limit = (lower_value * Constants.CONVERSION_FACTORS[lower_units]) \
// Constants.CONVERSION_FACTORS[upper_units]
counter = 0
while inf_limit > upper_spin_box.maximum():
counter += 1
inf_limit //= 1000
if upper_spin_box.minimum() != inf_limit:
upper_spin_box.setMinimum(inf_limit)
if counter > 0:
new_unit = unit_conversion[upper_units][counter - 1]
upper_combo_box.disconnect()
upper_combo_box.setCurrentText(new_unit)
upper_combo_box.currentTextChanged.connect(
partial(self.set_min_value_upper_limit,
lower_combo_box,
lower_spin_box,
upper_combo_box,
upper_spin_box)
)
@pyqtSlot()
def set_band_filter_label(self,
activate_low_btn,
lower_spinbox,
lower_unit,
lower_confidence,
activate_up_btn,
upper_spinbox,
upper_unit,
upper_confidence,
range_lbl):
activate_low = False
activate_high = False
color = Constants.INACTIVE_COLOR
title = ''
to_display = ''
if activate_low_btn.isChecked():
to_display += str(lower_spinbox.value()) + ' ' + lower_unit.currentText()
activate_low = True
color = Constants.ACTIVE_COLOR
if lower_confidence.value() != 0:
to_display += ' - ' + str(lower_confidence.value()) + ' %'
else:
to_display += 'DC'
to_display += ' ÷ '
if activate_up_btn.isChecked():
to_display += str(upper_spinbox.value()) + ' ' + upper_unit.currentText()
activate_high = True
color = Constants.ACTIVE_COLOR
if upper_confidence.value() != 0:
to_display += ' + ' + str(upper_confidence.value()) + ' %'
else:
to_display += 'INF'
if activate_low and activate_high:
title = 'Band-pass\n\n'
elif activate_low and not activate_high:
title = 'Low-pass\n\n'
elif not activate_low and activate_high:
title = 'High-pass\n\n'
else:
title = "Selected range:\n\n"
to_display = "Inactive"
to_display = title + to_display
range_lbl.setText(to_display)
range_lbl.setStyleSheet(f'color: {color};')
@pyqtSlot()
def activate_if_toggled(self, radio_btn, *widgets):
toggled = True if radio_btn.isChecked() else False
for w in widgets[:-1]: # Neglect the bool coming from the emitted signal.
w.setEnabled(toggled)
@pyqtSlot()
def display_signals(self):
self.result_list.clear()
text = self.search_bar.text()
available_signals = 0
for signal in self.signal_names:
if text.lower() in signal.lower() and \
self.frequency_filters_ok(signal) and \
self.band_filters_ok(signal) and \
self.category_filters_ok(signal) and \
self.mode_filters_ok(signal):
self.result_list.addItem(signal)
available_signals += 1
self.update_status_tip(available_signals)
def update_status_tip(self, available_signals):
if available_signals < self.total_signals:
self.statusbar.setStyleSheet(f'color: {Constants.ACTIVE_COLOR}')
else:
self.statusbar.setStyleSheet('color: #ffffff')
self.statusbar.showMessage(f"{available_signals} out of {self.total_signals} signals displayed.")
@pyqtSlot()
def reset_fb_filters(self, ftype):
if ftype != 'freq' and ftype != 'band':
raise ValueError("Wrong ftype in function 'reset_fb_filters'")
apply_remove_btn = getattr(self, 'apply_remove_' + ftype + '_filter_btn')
include_undef_btn = getattr(self, 'include_undef_' + ftype + 's')
activate_low = getattr(self, 'activate_low_' + ftype + '_filter_btn')
activate_up = getattr(self, 'activate_up_' + ftype + '_filter_btn')
lower_unit = getattr(self, 'lower_' + ftype + '_filter_unit')
upper_unit = getattr(self, 'upper_' + ftype + '_filter_unit')
lower_spinbox = getattr(self, 'lower_' + ftype + '_spinbox')
upper_spinbox = getattr(self, 'upper_' + ftype + '_spinbox')
lower_confidence = getattr(self, 'lower_' + ftype + '_confidence')
upper_confidence = getattr(self, 'lower_' + ftype + '_confidence')
default_val = 1 if ftype == 'freq' else 5000
if ftype == 'freq':
for f in self.frequency_filters_btns:
if f.isChecked():
f.setChecked(False)
reset_apply_remove_btn(apply_remove_btn)
if include_undef_btn.isChecked():
include_undef_btn.setChecked(False)
reset_apply_remove_btn(activate_low)
reset_apply_remove_btn(activate_up)
lower_unit.setCurrentText("MHz")
upper_unit.setCurrentText("MHz")
lower_spinbox.setValue(default_val)
upper_spinbox.setMinimum(1)
upper_spinbox.setValue(default_val)
lower_confidence.setValue(0)
upper_confidence.setValue(0)
@pyqtSlot()
def reset_cat_filters(self):
reset_apply_remove_btn(self.apply_remove_cat_filter_btn)
for f in self.cat_filter_btns:
f.setChecked(False) if f.isChecked() else None
self.cat_at_least_one.setChecked(True)
@pyqtSlot()
def reset_mode_filters(self):
reset_apply_remove_btn(self.apply_remove_mode_filter_btn)
for item in self.mode_tree_widget.selectedItems():
item.setSelected(False)
if self.include_unknown_modes_btn.isChecked():
self.include_unknown_modes_btn.setChecked(False)
def frequency_filters_ok(self, signal_name):
if not self.apply_remove_freq_filter_btn.isChecked():
return True
undef_freq = self.is_undef_freq(self.db.loc[signal_name])
if undef_freq:
if self.include_undef_freqs.isChecked():
return True
else:
return False
signal_freqs = (int(self.db.at[signal_name, "inf_freq"]),
int(self.db.at[signal_name, "sup_freq"]))
band_filter_ok = False
any_checked = False
for btn, band_limits in zip(self.frequency_filters_btns, Constants.BANDS):
if btn.isChecked():
any_checked = True
if signal_freqs[0] < band_limits.upper and signal_freqs[1] >= band_limits.lower:
band_filter_ok = True
lower_limit_ok = True
upper_limit_ok = True
if self.activate_low_freq_filter_btn.isChecked():
if not signal_freqs[1] >= self.filters_ok(self.lower_freq_spinbox,
self.lower_freq_filter_unit,
self.lower_freq_confidence, -1):
lower_limit_ok = False
if self.activate_up_freq_filter_btn.isChecked():
if not signal_freqs[0] < self.filters_ok(self.upper_freq_spinbox,
self.upper_freq_filter_unit,
self.upper_freq_confidence):
upper_limit_ok = False
if any_checked:
return band_filter_ok and lower_limit_ok and upper_limit_ok
else:
return lower_limit_ok and upper_limit_ok
def band_filters_ok(self, signal_name):
if not self.apply_remove_band_filter_btn.isChecked():
return True
undef_band = self.is_undef_band(self.db.loc[signal_name])
if undef_band:
if self.include_undef_bands.isChecked():
return True
else:
return False
signal_bands = (int(self.db.at[signal_name, "inf_band"]),
int(self.db.at[signal_name, "sup_band"]))
lower_limit_ok = True
upper_limit_ok = True
if self.activate_low_band_filter_btn.isChecked():
if not signal_bands[1] >= self.filters_ok(self.lower_band_spinbox,
self.lower_band_filter_unit,
self.lower_band_confidence, -1):
lower_limit_ok = False
if self.activate_up_band_filter_btn.isChecked():
if not signal_bands[0] < self.filters_ok(self.upper_band_spinbox,
self.upper_band_filter_unit,
self.upper_band_confidence):
upper_limit_ok = False
return lower_limit_ok and upper_limit_ok
def category_filters_ok(self, signal_name):
if not self.apply_remove_cat_filter_btn.isChecked():
return True
cat_code = self.db.at[signal_name, 'category_code']
cat_checked = 0
positive_cases = 0
for index, cat in enumerate(self.cat_filter_btns):
if cat.isChecked():
cat_checked += 1
if cat_code[index] == '1':
positive_cases += 1
if self.cat_at_least_one.isChecked():
return positive_cases > 0
else:
return cat_checked == positive_cases and cat_checked > 0
def mode_filters_ok(self, signal_name):
if not self.apply_remove_mode_filter_btn.isChecked():
return True
signal_mode = self.db.at[signal_name, "mode"]
if signal_mode == Constants.UNKNOWN:
if self.include_unknown_modes_btn.isChecked():
return True
else:
return False
selected_items = [item for item in self.mode_tree_widget.selectedItems()]
selected_items_text = [i.text(0) for i in selected_items]
parents = [item for item in selected_items_text if item in Constants.MODES.keys()]
children = [item for item in selected_items_text if item not in parents]
ok = []
for item in selected_items:
if item.text(0) in parents:
ok.append(item.text(0) in signal_mode)
elif not item.parent().isSelected():
ok.append(item.text(0) == signal_mode)
return any(ok)
@staticmethod
def filters_ok(spinbox, filter_unit, confidence, sign = 1):
band_filter = spinbox.value() * Constants.CONVERSION_FACTORS[filter_unit.currentText()]
return band_filter + sign * (confidence.value() * band_filter) // 100
@pyqtSlot(QListWidgetItem, QListWidgetItem)
def display_specs(self, item, previous_item):
self.display_spectrogram()
if item:
self.current_signal_name = item.text()
self.name_lab.setText(self.current_signal_name)
self.name_lab.setAlignment(Qt.AlignHCenter)
current_signal = self.db.loc[self.current_signal_name]
self.url_button.setEnabled(True)
if not current_signal.at["url_clicked"]:
self.url_button.setStyleSheet(f"color: {self.url_button.colors.active};")
else:
self.url_button.setStyleSheet(f"color: {self.url_button.colors.clicked};")
category_code = current_signal.at["category_code"]
undef_freq = self.is_undef_freq(current_signal)
undef_band = self.is_undef_band(current_signal)
if not undef_freq:
self.freq_lab.setText(self.format_numbers(
current_signal.at["inf_freq"],
current_signal.at["sup_freq"])
)
else:
self.freq_lab.setText("Undefined")
if not undef_band:
self.band_lab.setText(self.format_numbers(
current_signal.at["inf_band"],
current_signal.at["sup_band"])
)
else:
self.band_lab.setText("Undefined")
self.mode_lab.setText(current_signal.at["mode"])
self.modul_lab.setText(current_signal.at["modulation"])
self.loc_lab.setText(current_signal.at["location"])
self.acf_lab.setText(current_signal.at["acf"])
self.description_text.setText(current_signal.at["description"])
for cat, cat_lab in zip(category_code, self.category_labels):
if cat == '0':
cat_lab.setStyleSheet(f"color: {Constants.INACTIVE_COLOR};")
elif cat == '1':
cat_lab.setStyleSheet(f"color: {Constants.ACTIVE_COLOR};")
self.set_band_range(current_signal)
self.audio_widget.set_audio_player(self.current_signal_name)
else:
self.url_button.setEnabled(False)
self.url_button.setStyleSheet(f"color: {self.url_button.colors.inactive};")
self.current_signal_name = ''
self.name_lab.setText("No signal")
self.name_lab.setAlignment(Qt.AlignHCenter)
for lab in self.property_labels:
lab.setText("N/A")
for lab in self.category_labels:
lab.setStyleSheet(f"color: {Constants.INACTIVE_COLOR};")
self.set_band_range()
self.audio_widget.set_audio_player()
@staticmethod
def is_undef_freq(current_signal):
lower_freq = current_signal.at["inf_freq"]
upper_freq = current_signal.at["sup_freq"]
return lower_freq == 'N/A' or upper_freq == 'N/A'
@staticmethod
def is_undef_band(current_signal):
lower_band = current_signal.at["inf_band"]
upper_band = current_signal.at["sup_band"]
return lower_band == 'N/A' or upper_band == 'N/A'
@classmethod
def format_numbers(cls, lower, upper):
units = {1: 'Hz', 1000: 'kHz', 10**6: 'MHz', 10**9: 'GHz'}
lower_factor = cls.change_unit(lower)
upper_factor = cls.change_unit(upper)
pre_lower = lower
pre_upper = upper
lower = int(lower) / lower_factor
upper = int(upper) / upper_factor
if lower.is_integer():
lower = int(lower)
if upper.is_integer():
upper = int(upper)
if pre_lower != pre_upper:
return f"{lower:,} {units[lower_factor]} - {upper:,} {units[upper_factor]}"
else:
return f"{lower:,} {units[lower_factor]}"
@staticmethod
def change_unit(num):
digits = len(num)
if digits < 4:
return 1
elif digits < 7:
return 1000
elif digits < 10:
return 10**6
else:
return 10**9
def display_spectrogram(self):
default_pic = os.path.join(Constants.ICONS_FOLDER, "nosignalselected.png")
item = self.result_list.currentItem()
if item:
spectrogram_name = item.text()
path_spectr = os.path.join(Constants.DATA_FOLDER, Constants.SPECTRA_FOLDER, spectrogram_name + ".png")
if not QFileInfo(path_spectr).exists():
path_spectr = os.path.join(Constants.ICONS_FOLDER, "spectrumnotavailable.png")
else:
path_spectr = default_pic
self.spectrogram.setPixmap(QPixmap(path_spectr))
@staticmethod
def activate_band_category(band_label, activate = True):
color = Constants.ACTIVE_COLOR if activate else Constants.INACTIVE_COLOR
for label in band_label:
label.setStyleSheet(f"color: {color};")
def set_band_range(self, current_signal = None):
if current_signal is not None and not self.is_undef_freq(current_signal):
lower_freq = int(current_signal.at["inf_freq"])
upper_freq = int(current_signal.at["sup_freq"])
zipped = list(zip(Constants.BANDS, self.band_labels))
for i, w in enumerate(zipped):
band, band_label = w
if lower_freq >= band.lower and lower_freq < band.upper:
self.activate_band_category(band_label)
for uband, uband_label in zipped[i + 1:]:
if upper_freq > uband.lower:
self.activate_band_category(uband_label)
else:
self.activate_band_category(uband_label, False)
break
else:
self.activate_band_category(band_label, False)
else:
for band_label in self.band_labels:
self.activate_band_category(band_label, False)
@pyqtSlot()
def reset_all_filters(self):
self.reset_frequency_filters_btn.clicked.emit()
self.reset_band_filters_btn.clicked.emit()
self.reset_cat_filters_btn.clicked.emit()
self.reset_mode_filters_btn.clicked.emit()
@pyqtSlot()
def go_to_web_page_signal(self):
if self.current_signal_name:
self.url_button.setStyleSheet(f"color: {self.url_button.colors.clicked}")
webbrowser.open(self.db.at[self.current_signal_name, "url"])
self.db.at[self.current_signal_name, "url_clicked"] = True
def closeEvent(self, event):
if self.download_window.isVisible():
self.download_window.close()
super().closeEvent(event)
if __name__ == '__main__':
my_app = QApplication(sys.argv)
w = MyApp()
sys.exit(my_app.exec_())