Merge branch 'async_download'
This commit is contained in:
265
artemis.py
265
artemis.py
@@ -6,6 +6,7 @@ import sys
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from pandas import read_csv
|
from pandas import read_csv
|
||||||
|
|
||||||
from PyQt5.QtWidgets import (QMainWindow,
|
from PyQt5.QtWidgets import (QMainWindow,
|
||||||
QApplication,
|
QApplication,
|
||||||
qApp,
|
qApp,
|
||||||
@@ -42,7 +43,8 @@ from utilities import (checksum_ok,
|
|||||||
format_numbers,
|
format_numbers,
|
||||||
resource_path,)
|
resource_path,)
|
||||||
|
|
||||||
# import icon_rc
|
import icon_rc
|
||||||
|
|
||||||
|
|
||||||
qt_creator_file = resource_path("artemis.ui")
|
qt_creator_file = resource_path("artemis.ui")
|
||||||
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
|
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
|
||||||
@@ -53,6 +55,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.set_initial_size()
|
self.set_initial_size()
|
||||||
|
self.closing = False
|
||||||
self.download_window = DownloadWindow()
|
self.download_window = DownloadWindow()
|
||||||
self.download_window.complete.connect(self.show_downloaded_signals)
|
self.download_window.complete.connect(self.show_downloaded_signals)
|
||||||
self.actionExit.triggered.connect(qApp.quit)
|
self.actionExit.triggered.connect(qApp.quit)
|
||||||
@@ -62,35 +65,44 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.current_signal_name = ''
|
self.current_signal_name = ''
|
||||||
self.signal_names = []
|
self.signal_names = []
|
||||||
self.total_signals = 0
|
self.total_signals = 0
|
||||||
self.switchable_r_labels = SwitchableLabelsIterable(self.r0_now_lbl,
|
self.switchable_r_labels = SwitchableLabelsIterable(
|
||||||
|
self.r0_now_lbl,
|
||||||
self.r1_now_lbl,
|
self.r1_now_lbl,
|
||||||
self.r2_now_lbl,
|
self.r2_now_lbl,
|
||||||
self.r3_now_lbl,
|
self.r3_now_lbl,
|
||||||
self.r4_now_lbl,
|
self.r4_now_lbl,
|
||||||
self.r5_now_lbl,)
|
self.r5_now_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.switchable_s_labels = SwitchableLabelsIterable(self.s0_now_lbl,
|
self.switchable_s_labels = SwitchableLabelsIterable(
|
||||||
|
self.s0_now_lbl,
|
||||||
self.s1_now_lbl,
|
self.s1_now_lbl,
|
||||||
self.s2_now_lbl,
|
self.s2_now_lbl,
|
||||||
self.s3_now_lbl,
|
self.s3_now_lbl,
|
||||||
self.s4_now_lbl,
|
self.s4_now_lbl,
|
||||||
self.s5_now_lbl,)
|
self.s5_now_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.switchable_g_now_labels = SwitchableLabelsIterable(self.g0_now_lbl,
|
self.switchable_g_now_labels = SwitchableLabelsIterable(
|
||||||
|
self.g0_now_lbl,
|
||||||
self.g1_now_lbl,
|
self.g1_now_lbl,
|
||||||
self.g2_now_lbl,
|
self.g2_now_lbl,
|
||||||
self.g3_now_lbl,
|
self.g3_now_lbl,
|
||||||
self.g4_now_lbl,
|
self.g4_now_lbl,
|
||||||
self.g5_now_lbl)
|
self.g5_now_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.switchable_g_today_labels = SwitchableLabelsIterable(self.g0_today_lbl,
|
self.switchable_g_today_labels = SwitchableLabelsIterable(
|
||||||
|
self.g0_today_lbl,
|
||||||
self.g1_today_lbl,
|
self.g1_today_lbl,
|
||||||
self.g2_today_lbl,
|
self.g2_today_lbl,
|
||||||
self.g3_today_lbl,
|
self.g3_today_lbl,
|
||||||
self.g4_today_lbl,
|
self.g4_today_lbl,
|
||||||
self.g5_today_lbl)
|
self.g5_today_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.k_storm_labels = SwitchableLabelsIterable(self.k_ex_sev_storm_lbl,
|
self.k_storm_labels = SwitchableLabelsIterable(
|
||||||
|
self.k_ex_sev_storm_lbl,
|
||||||
self.k_very_sev_storm_lbl,
|
self.k_very_sev_storm_lbl,
|
||||||
self.k_sev_storm_lbl,
|
self.k_sev_storm_lbl,
|
||||||
self.k_maj_storm_lbl,
|
self.k_maj_storm_lbl,
|
||||||
@@ -99,16 +111,20 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.k_unsettled_lbl,
|
self.k_unsettled_lbl,
|
||||||
self.k_quiet_lbl,
|
self.k_quiet_lbl,
|
||||||
self.k_very_quiet_lbl,
|
self.k_very_quiet_lbl,
|
||||||
self.k_inactive_lbl)
|
self.k_inactive_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.a_storm_labels = SwitchableLabelsIterable(self.a_sev_storm_lbl,
|
self.a_storm_labels = SwitchableLabelsIterable(
|
||||||
|
self.a_sev_storm_lbl,
|
||||||
self.a_maj_storm_lbl,
|
self.a_maj_storm_lbl,
|
||||||
self.a_min_storm_lbl,
|
self.a_min_storm_lbl,
|
||||||
self.a_active_lbl,
|
self.a_active_lbl,
|
||||||
self.a_unsettled_lbl,
|
self.a_unsettled_lbl,
|
||||||
self.a_quiet_lbl)
|
self.a_quiet_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.forecast_labels = (self.forecast_lbl_0,
|
self.forecast_labels = (
|
||||||
|
self.forecast_lbl_0,
|
||||||
self.forecast_lbl_1,
|
self.forecast_lbl_1,
|
||||||
self.forecast_lbl_2,
|
self.forecast_lbl_2,
|
||||||
self.forecast_lbl_3,
|
self.forecast_lbl_3,
|
||||||
@@ -116,7 +132,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.forecast_lbl_5,
|
self.forecast_lbl_5,
|
||||||
self.forecast_lbl_6,
|
self.forecast_lbl_6,
|
||||||
self.forecast_lbl_7,
|
self.forecast_lbl_7,
|
||||||
self.forecast_lbl_8)
|
self.forecast_lbl_8
|
||||||
|
)
|
||||||
|
|
||||||
for lab in self.forecast_labels:
|
for lab in self.forecast_labels:
|
||||||
lab.set_default_stylesheet()
|
lab.set_default_stylesheet()
|
||||||
@@ -191,27 +208,29 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
self.apply_remove_freq_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_freq_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
||||||
self.apply_remove_freq_filter_btn.set_slave_filters(
|
self.apply_remove_freq_filter_btn.set_slave_filters(
|
||||||
[
|
simple_ones=[
|
||||||
*self.frequency_filters_btns,
|
*self.frequency_filters_btns,
|
||||||
self.include_undef_freqs,
|
self.include_undef_freqs,
|
||||||
self.activate_low_freq_filter_btn,
|
self.activate_low_freq_filter_btn,
|
||||||
self.activate_up_freq_filter_btn,
|
self.activate_up_freq_filter_btn
|
||||||
],
|
],
|
||||||
self.activate_low_freq_filter_btn,
|
radio_1=self.activate_low_freq_filter_btn,
|
||||||
[
|
ruled_by_radio_1=[
|
||||||
self.lower_freq_spinbox,
|
self.lower_freq_spinbox,
|
||||||
self.lower_freq_filter_unit,
|
self.lower_freq_filter_unit,
|
||||||
self.lower_freq_confidence,
|
self.lower_freq_confidence
|
||||||
],
|
],
|
||||||
self.activate_up_freq_filter_btn,
|
radio_2=self.activate_up_freq_filter_btn,
|
||||||
[
|
ruled_by_radio_2=[
|
||||||
self.upper_freq_spinbox,
|
self.upper_freq_spinbox,
|
||||||
self.upper_freq_filter_unit,
|
self.upper_freq_filter_unit,
|
||||||
self.upper_freq_confidence,
|
self.upper_freq_confidence
|
||||||
],
|
]
|
||||||
)
|
)
|
||||||
self.apply_remove_freq_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_freq_filter_btn.clicked.connect(self.display_signals)
|
||||||
self.reset_frequency_filters_btn.clicked.connect(partial(self.reset_fb_filters, Ftype.FREQ))
|
self.reset_frequency_filters_btn.clicked.connect(
|
||||||
|
partial(self.reset_fb_filters, Ftype.FREQ)
|
||||||
|
)
|
||||||
|
|
||||||
# Manage bandwidth filters.
|
# Manage bandwidth filters.
|
||||||
|
|
||||||
@@ -265,33 +284,37 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.upper_band_confidence)
|
self.upper_band_confidence)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.apply_remove_band_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_band_filter_btn.set_texts(Constants.APPLY,
|
||||||
|
Constants.REMOVE)
|
||||||
self.apply_remove_band_filter_btn.set_slave_filters(
|
self.apply_remove_band_filter_btn.set_slave_filters(
|
||||||
[
|
simple_ones=[
|
||||||
self.include_undef_bands,
|
self.include_undef_bands,
|
||||||
self.activate_low_band_filter_btn,
|
self.activate_low_band_filter_btn,
|
||||||
self.activate_up_band_filter_btn,
|
self.activate_up_band_filter_btn
|
||||||
],
|
],
|
||||||
self.activate_low_band_filter_btn,
|
radio_1=self.activate_low_band_filter_btn,
|
||||||
[
|
ruled_by_radio_1=[
|
||||||
self.lower_band_spinbox,
|
self.lower_band_spinbox,
|
||||||
self.lower_band_filter_unit,
|
self.lower_band_filter_unit,
|
||||||
self.lower_band_confidence,
|
self.lower_band_confidence
|
||||||
],
|
],
|
||||||
self.activate_up_band_filter_btn,
|
radio_2=self.activate_up_band_filter_btn,
|
||||||
[
|
ruled_by_radio_2=[
|
||||||
self.upper_band_spinbox,
|
self.upper_band_spinbox,
|
||||||
self.upper_band_filter_unit,
|
self.upper_band_filter_unit,
|
||||||
self.upper_band_confidence,
|
self.upper_band_confidence
|
||||||
],
|
]
|
||||||
)
|
)
|
||||||
self.apply_remove_band_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_band_filter_btn.clicked.connect(self.display_signals)
|
||||||
self.reset_band_filters_btn.clicked.connect(partial(self.reset_fb_filters, Ftype.BAND))
|
self.reset_band_filters_btn.clicked.connect(
|
||||||
|
partial(self.reset_fb_filters, Ftype.BAND)
|
||||||
|
)
|
||||||
|
|
||||||
# Manage category filters
|
# Manage category filters
|
||||||
|
|
||||||
# Order matters!
|
# Order matters!
|
||||||
self.cat_filter_btns = [self.military_btn,
|
self.cat_filter_btns = [
|
||||||
|
self.military_btn,
|
||||||
self.radar_btn,
|
self.radar_btn,
|
||||||
self.active_btn,
|
self.active_btn,
|
||||||
self.inactive_btn,
|
self.inactive_btn,
|
||||||
@@ -307,12 +330,17 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.navigation_btn,
|
self.navigation_btn,
|
||||||
self.interfering_btn,
|
self.interfering_btn,
|
||||||
self.number_stations_btn,
|
self.number_stations_btn,
|
||||||
self.time_signal_btn,]
|
self.time_signal_btn
|
||||||
|
]
|
||||||
|
|
||||||
self.apply_remove_cat_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_cat_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
||||||
self.apply_remove_cat_filter_btn.set_slave_filters([*self.cat_filter_btns,
|
self.apply_remove_cat_filter_btn.set_slave_filters(
|
||||||
|
simple_ones=[
|
||||||
|
*self.cat_filter_btns,
|
||||||
self.cat_at_least_one,
|
self.cat_at_least_one,
|
||||||
self.cat_all])
|
self.cat_all
|
||||||
|
]
|
||||||
|
)
|
||||||
self.apply_remove_cat_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_cat_filter_btn.clicked.connect(self.display_signals)
|
||||||
self.reset_cat_filters_btn.clicked.connect(self.reset_cat_filters)
|
self.reset_cat_filters_btn.clicked.connect(self.reset_cat_filters)
|
||||||
|
|
||||||
@@ -322,7 +350,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
UrlColors = namedtuple("UrlColors", ["inactive", "active", "clicked"])
|
UrlColors = namedtuple("UrlColors", ["inactive", "active", "clicked"])
|
||||||
self.url_button.colors = UrlColors("#9f9f9f", "#4c75ff", "#942ccc")
|
self.url_button.colors = UrlColors("#9f9f9f", "#4c75ff", "#942ccc")
|
||||||
self.category_labels = [self.cat_mil,
|
self.category_labels = [
|
||||||
|
self.cat_mil,
|
||||||
self.cat_rad,
|
self.cat_rad,
|
||||||
self.cat_active,
|
self.cat_active,
|
||||||
self.cat_inactive,
|
self.cat_inactive,
|
||||||
@@ -338,15 +367,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.cat_navi,
|
self.cat_navi,
|
||||||
self.cat_interf,
|
self.cat_interf,
|
||||||
self.cat_num_stat,
|
self.cat_num_stat,
|
||||||
self.cat_time_sig,]
|
self.cat_time_sig
|
||||||
|
]
|
||||||
|
|
||||||
self.property_labels = [self.freq_lab,
|
self.property_labels = [
|
||||||
|
self.freq_lab,
|
||||||
self.band_lab,
|
self.band_lab,
|
||||||
self.mode_lab,
|
self.mode_lab,
|
||||||
self.modul_lab,
|
self.modul_lab,
|
||||||
self.loc_lab,
|
self.loc_lab,
|
||||||
self.acf_lab,
|
self.acf_lab,
|
||||||
self.description_text,]
|
self.description_text
|
||||||
|
]
|
||||||
|
|
||||||
self.url_button.clicked.connect(self.go_to_web_page_signal)
|
self.url_button.clicked.connect(self.go_to_web_page_signal)
|
||||||
|
|
||||||
@@ -356,8 +388,12 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.mode_tree_widget.itemSelectionChanged.connect(self.manage_mode_selections)
|
self.mode_tree_widget.itemSelectionChanged.connect(self.manage_mode_selections)
|
||||||
self.reset_mode_filters_btn.clicked.connect(self.reset_mode_filters)
|
self.reset_mode_filters_btn.clicked.connect(self.reset_mode_filters)
|
||||||
self.apply_remove_mode_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_mode_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
||||||
self.apply_remove_mode_filter_btn.set_slave_filters([self.mode_tree_widget,
|
self.apply_remove_mode_filter_btn.set_slave_filters(
|
||||||
self.include_unknown_modes_btn])
|
simple_ones=[
|
||||||
|
self.mode_tree_widget,
|
||||||
|
self.include_unknown_modes_btn
|
||||||
|
]
|
||||||
|
)
|
||||||
self.apply_remove_mode_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_mode_filter_btn.clicked.connect(self.display_signals)
|
||||||
|
|
||||||
# Set modulation filter screen.
|
# Set modulation filter screen.
|
||||||
@@ -365,8 +401,12 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.modulation_list.addItems(Constants.MODULATIONS)
|
self.modulation_list.addItems(Constants.MODULATIONS)
|
||||||
self.search_bar_modulation.textEdited.connect(self.show_matching_modulations)
|
self.search_bar_modulation.textEdited.connect(self.show_matching_modulations)
|
||||||
self.apply_remove_modulation_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_modulation_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
||||||
self.apply_remove_modulation_filter_btn.set_slave_filters([self.search_bar_modulation,
|
self.apply_remove_modulation_filter_btn.set_slave_filters(
|
||||||
self.modulation_list])
|
simple_ones=[
|
||||||
|
self.search_bar_modulation,
|
||||||
|
self.modulation_list
|
||||||
|
]
|
||||||
|
)
|
||||||
self.apply_remove_modulation_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_modulation_filter_btn.clicked.connect(self.display_signals)
|
||||||
self.reset_modulation_filters_btn.clicked.connect(self.reset_modulation_filters)
|
self.reset_modulation_filters_btn.clicked.connect(self.reset_modulation_filters)
|
||||||
self.modulation_list.itemClicked.connect(self.remove_if_unselected_modulation)
|
self.modulation_list.itemClicked.connect(self.remove_if_unselected_modulation)
|
||||||
@@ -376,21 +416,32 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.locations_list.addItems(Constants.LOCATIONS)
|
self.locations_list.addItems(Constants.LOCATIONS)
|
||||||
self.search_bar_location.textEdited.connect(self.show_matching_locations)
|
self.search_bar_location.textEdited.connect(self.show_matching_locations)
|
||||||
self.apply_remove_location_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_location_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
||||||
self.apply_remove_location_filter_btn.set_slave_filters([self.search_bar_location,
|
self.apply_remove_location_filter_btn.set_slave_filters(
|
||||||
self.locations_list])
|
simple_ones=[
|
||||||
|
self.search_bar_location,
|
||||||
|
self.locations_list
|
||||||
|
]
|
||||||
|
)
|
||||||
self.apply_remove_location_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_location_filter_btn.clicked.connect(self.display_signals)
|
||||||
self.reset_location_filters_btn.clicked.connect(self.reset_location_filters)
|
self.reset_location_filters_btn.clicked.connect(self.reset_location_filters)
|
||||||
self.locations_list.itemClicked.connect(self.remove_if_unselected_location)
|
self.locations_list.itemClicked.connect(self.remove_if_unselected_location)
|
||||||
|
|
||||||
# Set ACF filter screen.
|
# Set ACF filter screen.
|
||||||
self.apply_remove_acf_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
self.apply_remove_acf_filter_btn.set_texts(Constants.APPLY, Constants.REMOVE)
|
||||||
self.apply_remove_acf_filter_btn.set_slave_filters([self.include_undef_acf, self.acf_spinbox, self.acf_confidence])
|
self.apply_remove_acf_filter_btn.set_slave_filters(
|
||||||
|
simple_ones=[
|
||||||
|
self.include_undef_acf,
|
||||||
|
self.acf_spinbox,
|
||||||
|
self.acf_confidence
|
||||||
|
]
|
||||||
|
)
|
||||||
self.apply_remove_acf_filter_btn.clicked.connect(self.display_signals)
|
self.apply_remove_acf_filter_btn.clicked.connect(self.display_signals)
|
||||||
self.reset_acf_filters_btn.clicked.connect(self.reset_acf_filters)
|
self.reset_acf_filters_btn.clicked.connect(self.reset_acf_filters)
|
||||||
self.acf_info_btn.clicked.connect(lambda : webbrowser.open(Constants.ACF_DOCS))
|
self.acf_info_btn.clicked.connect(lambda : webbrowser.open(Constants.ACF_DOCS))
|
||||||
|
|
||||||
connect_events_to_func(
|
connect_events_to_func(
|
||||||
events_to_connect = [self.acf_spinbox.valueChanged, self.acf_confidence.valueChanged],
|
events_to_connect=[self.acf_spinbox.valueChanged,
|
||||||
|
self.acf_confidence.valueChanged],
|
||||||
fun_to_connect=self.set_acf_interval_label,
|
fun_to_connect=self.set_acf_interval_label,
|
||||||
fun_args=None
|
fun_args=None
|
||||||
)
|
)
|
||||||
@@ -405,14 +456,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
# Left list widget and search bar.
|
# Left list widget and search bar.
|
||||||
self.search_bar.textChanged.connect(self.display_signals)
|
self.search_bar.textChanged.connect(self.display_signals)
|
||||||
self.result_list.currentItemChanged.connect(self.display_specs)
|
self.result_list.currentItemChanged.connect(self.display_specs)
|
||||||
self.result_list.itemDoubleClicked.connect(lambda: self.main_tab.setCurrentWidget(self.signal_properties_tab))
|
self.result_list.itemDoubleClicked.connect(
|
||||||
self.audio_widget = AudioPlayer(self.play,
|
lambda: self.main_tab.setCurrentWidget(self.signal_properties_tab)
|
||||||
|
)
|
||||||
|
self.audio_widget = AudioPlayer(
|
||||||
|
self.play,
|
||||||
self.pause,
|
self.pause,
|
||||||
self.stop,
|
self.stop,
|
||||||
self.volume,
|
self.volume,
|
||||||
self.audio_progress,
|
self.audio_progress,
|
||||||
self.active_color,
|
self.active_color,
|
||||||
self.inactive_color)
|
self.inactive_color
|
||||||
|
)
|
||||||
|
|
||||||
BandLabel = namedtuple("BandLabel", ["left", "center", "right"])
|
BandLabel = namedtuple("BandLabel", ["left", "center", "right"])
|
||||||
self.band_labels = [
|
self.band_labels = [
|
||||||
@@ -430,7 +485,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Space weather
|
# Space weather
|
||||||
self.info_now_btn.clicked.connect(lambda : webbrowser.open(Constants.FORECAST_INFO))
|
self.info_now_btn.clicked.connect(
|
||||||
|
lambda : webbrowser.open(Constants.FORECAST_INFO)
|
||||||
|
)
|
||||||
self.update_now_bar.clicked.connect(self.start_update_space_weather)
|
self.update_now_bar.clicked.connect(self.start_update_space_weather)
|
||||||
self.update_now_bar.set_idle()
|
self.update_now_bar.set_idle()
|
||||||
self.space_weather_data = SpaceWeatherData()
|
self.space_weather_data = SpaceWeatherData()
|
||||||
@@ -591,7 +648,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
label.pixmap = pixmap
|
label.pixmap = pixmap
|
||||||
label.make_transparent()
|
label.make_transparent()
|
||||||
label.apply_pixmap()
|
label.apply_pixmap()
|
||||||
else:
|
elif not self.closing:
|
||||||
pop_up(self, title=Messages.BAD_DOWNLOAD,
|
pop_up(self, title=Messages.BAD_DOWNLOAD,
|
||||||
text=Messages.BAD_DOWNLOAD_MSG).show()
|
text=Messages.BAD_DOWNLOAD_MSG).show()
|
||||||
self.space_weather_data.remove_data()
|
self.space_weather_data.remove_data()
|
||||||
@@ -600,7 +657,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
def go_to_gfd(self, by):
|
def go_to_gfd(self, by):
|
||||||
query = "/?q="
|
query = "/?q="
|
||||||
if by is GfdType.FREQ:
|
if by is GfdType.FREQ:
|
||||||
value_in_mhz = self.freq_gfd.value() * Constants.CONVERSION_FACTORS[self.unit_freq_gfd.currentText()] / Constants.CONVERSION_FACTORS["MHz"]
|
value_in_mhz = self.freq_gfd.value() \
|
||||||
|
* Constants.CONVERSION_FACTORS[self.unit_freq_gfd.currentText()] \
|
||||||
|
/ Constants.CONVERSION_FACTORS["MHz"]
|
||||||
query += str(value_in_mhz)
|
query += str(value_in_mhz)
|
||||||
elif by is GfdType.LOC:
|
elif by is GfdType.LOC:
|
||||||
query += self.gfd_line_edit.text()
|
query += self.gfd_line_edit.text()
|
||||||
@@ -654,8 +713,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
item.child(i).setSelected(True)
|
item.child(i).setSelected(True)
|
||||||
|
|
||||||
def set_initial_size(self):
|
def set_initial_size(self):
|
||||||
"""Function to handle high resolution screens. The function sets bigger sizes
|
"""Function to handle high resolution screens. The function sets bigger
|
||||||
for all the relevant fixed-size widgets."""
|
sizes for all the relevant fixed-size widgets."""
|
||||||
d = QDesktopWidget().availableGeometry()
|
d = QDesktopWidget().availableGeometry()
|
||||||
w = d.width()
|
w = d.width()
|
||||||
h = d.height()
|
h = d.height()
|
||||||
@@ -780,7 +839,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
header=None,
|
header=None,
|
||||||
index_col=0,
|
index_col=0,
|
||||||
dtype={name: str for name in Database.STRINGS},
|
dtype={name: str for name in Database.STRINGS},
|
||||||
names = names,)
|
names=names)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.search_bar.setDisabled(True)
|
self.search_bar.setDisabled(True)
|
||||||
answer = pop_up(self, title=Messages.NO_DB,
|
answer = pop_up(self, title=Messages.NO_DB,
|
||||||
@@ -824,11 +883,13 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
upper_combo_box.disconnect()
|
upper_combo_box.disconnect()
|
||||||
upper_combo_box.setCurrentText(new_unit)
|
upper_combo_box.setCurrentText(new_unit)
|
||||||
upper_combo_box.currentTextChanged.connect(
|
upper_combo_box.currentTextChanged.connect(
|
||||||
partial(self.set_min_value_upper_limit,
|
partial(
|
||||||
|
self.set_min_value_upper_limit,
|
||||||
lower_combo_box,
|
lower_combo_box,
|
||||||
lower_spin_box,
|
lower_spin_box,
|
||||||
upper_combo_box,
|
upper_combo_box,
|
||||||
upper_spin_box)
|
upper_spin_box
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@@ -853,7 +914,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
min_value = lower_spinbox.value()
|
min_value = lower_spinbox.value()
|
||||||
if lower_confidence.value() != 0:
|
if lower_confidence.value() != 0:
|
||||||
min_value -= lower_spinbox.value() * lower_confidence.value() / 100
|
min_value -= lower_spinbox.value() * lower_confidence.value() / 100
|
||||||
to_display += str(round(min_value, Constants.MAX_DIGITS)) + ' ' + lower_unit.currentText()
|
to_display += str(round(min_value, Constants.MAX_DIGITS)) \
|
||||||
|
+ ' ' + lower_unit.currentText()
|
||||||
else:
|
else:
|
||||||
to_display += 'DC'
|
to_display += 'DC'
|
||||||
to_display += Constants.RANGE_SEPARATOR
|
to_display += Constants.RANGE_SEPARATOR
|
||||||
@@ -863,7 +925,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
color = self.active_color
|
color = self.active_color
|
||||||
if upper_confidence.value() != 0:
|
if upper_confidence.value() != 0:
|
||||||
max_value += upper_spinbox.value() * upper_confidence.value() / 100
|
max_value += upper_spinbox.value() * upper_confidence.value() / 100
|
||||||
to_display += str(round(max_value, Constants.MAX_DIGITS)) + ' ' + upper_unit.currentText()
|
to_display += str(round(max_value, Constants.MAX_DIGITS)) + ' ' \
|
||||||
|
+ upper_unit.currentText()
|
||||||
else:
|
else:
|
||||||
to_display += 'INF'
|
to_display += 'INF'
|
||||||
if activate_low and activate_high:
|
if activate_low and activate_high:
|
||||||
@@ -883,8 +946,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
def set_acf_interval_label(self):
|
def set_acf_interval_label(self):
|
||||||
tolerance = self.acf_spinbox.value() * self.acf_confidence.value() / 100
|
tolerance = self.acf_spinbox.value() * self.acf_confidence.value() / 100
|
||||||
if tolerance > 0:
|
if tolerance > 0:
|
||||||
to_display = f"Selected range:\n\n{round(self.acf_spinbox.value() - tolerance, Constants.MAX_DIGITS)}" +\
|
val = round(self.acf_spinbox.value() - tolerance, Constants.MAX_DIGITS)
|
||||||
Constants.RANGE_SEPARATOR + f"{round(self.acf_spinbox.value() + tolerance, Constants.MAX_DIGITS)} ms"
|
to_display = f"Selected range:\n\n{val}" + Constants.RANGE_SEPARATOR \
|
||||||
|
+ f"{round(self.acf_spinbox.value() + tolerance, Constants.MAX_DIGITS)} ms"
|
||||||
else:
|
else:
|
||||||
to_display = f"Selected value:\n\n{self.acf_spinbox.value()} ms"
|
to_display = f"Selected value:\n\n{self.acf_spinbox.value()} ms"
|
||||||
self.acf_range_lbl.setText(to_display)
|
self.acf_range_lbl.setText(to_display)
|
||||||
@@ -922,12 +986,15 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.statusbar.setStyleSheet(f'color: {self.active_color}')
|
self.statusbar.setStyleSheet(f'color: {self.active_color}')
|
||||||
else:
|
else:
|
||||||
self.statusbar.setStyleSheet(f'color: {self.inactive_color}')
|
self.statusbar.setStyleSheet(f'color: {self.inactive_color}')
|
||||||
self.statusbar.showMessage(f"{available_signals} out of {self.total_signals} signals displayed.")
|
self.statusbar.showMessage(
|
||||||
|
f"{available_signals} out of {self.total_signals} signals displayed."
|
||||||
|
)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def reset_fb_filters(self, ftype):
|
def reset_fb_filters(self, ftype):
|
||||||
if ftype != Ftype.FREQ and ftype != Ftype.BAND:
|
if ftype != Ftype.FREQ and ftype != Ftype.BAND:
|
||||||
raise ValueError("Wrong ftype in function 'reset_fb_filters'")
|
raise ValueError("Wrong ftype in function 'reset_fb_filters'")
|
||||||
|
|
||||||
apply_remove_btn = getattr(self, 'apply_remove_' + ftype + '_filter_btn')
|
apply_remove_btn = getattr(self, 'apply_remove_' + ftype + '_filter_btn')
|
||||||
include_undef_btn = getattr(self, 'include_undef_' + ftype + 's')
|
include_undef_btn = getattr(self, 'include_undef_' + ftype + 's')
|
||||||
activate_low = getattr(self, 'activate_low_' + ftype + '_filter_btn')
|
activate_low = getattr(self, 'activate_low_' + ftype + '_filter_btn')
|
||||||
@@ -938,6 +1005,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
upper_spinbox = getattr(self, 'upper_' + ftype + '_spinbox')
|
upper_spinbox = getattr(self, 'upper_' + ftype + '_spinbox')
|
||||||
lower_confidence = getattr(self, 'lower_' + ftype + '_confidence')
|
lower_confidence = getattr(self, 'lower_' + ftype + '_confidence')
|
||||||
upper_confidence = getattr(self, 'lower_' + ftype + '_confidence')
|
upper_confidence = getattr(self, 'lower_' + ftype + '_confidence')
|
||||||
|
|
||||||
default_val = 1 if ftype == Ftype.FREQ else 5000
|
default_val = 1 if ftype == Ftype.FREQ else 5000
|
||||||
if ftype == Ftype.FREQ:
|
if ftype == Ftype.FREQ:
|
||||||
for f in self.frequency_filters_btns:
|
for f in self.frequency_filters_btns:
|
||||||
@@ -1013,8 +1081,10 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
signal_freqs = (int(self.db.at[signal_name, Signal.INF_FREQ]),
|
signal_freqs = (
|
||||||
int(self.db.at[signal_name, Signal.SUP_FREQ]))
|
int(self.db.at[signal_name, Signal.INF_FREQ]),
|
||||||
|
int(self.db.at[signal_name, Signal.SUP_FREQ])
|
||||||
|
)
|
||||||
|
|
||||||
band_filter_ok = False
|
band_filter_ok = False
|
||||||
any_checked = False
|
any_checked = False
|
||||||
@@ -1050,8 +1120,10 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
signal_bands = (int(self.db.at[signal_name, Signal.INF_BAND]),
|
signal_bands = (
|
||||||
int(self.db.at[signal_name, Signal.SUP_BAND]))
|
int(self.db.at[signal_name, Signal.INF_BAND]),
|
||||||
|
int(self.db.at[signal_name, Signal.SUP_BAND])
|
||||||
|
)
|
||||||
|
|
||||||
lower_limit_ok = True
|
lower_limit_ok = True
|
||||||
upper_limit_ok = True
|
upper_limit_ok = True
|
||||||
@@ -1150,21 +1222,31 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
current_signal = self.db.loc[self.current_signal_name]
|
current_signal = self.db.loc[self.current_signal_name]
|
||||||
self.url_button.setEnabled(True)
|
self.url_button.setEnabled(True)
|
||||||
if not current_signal.at[Signal.WIKI_CLICKED]:
|
if not current_signal.at[Signal.WIKI_CLICKED]:
|
||||||
self.url_button.setStyleSheet(f"color: {self.url_button.colors.active};")
|
self.url_button.setStyleSheet(
|
||||||
|
f"color: {self.url_button.colors.active};"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.url_button.setStyleSheet(f"color: {self.url_button.colors.clicked};")
|
self.url_button.setStyleSheet(
|
||||||
|
f"color: {self.url_button.colors.clicked};"
|
||||||
|
)
|
||||||
category_code = current_signal.at[Signal.CATEGORY_CODE]
|
category_code = current_signal.at[Signal.CATEGORY_CODE]
|
||||||
undef_freq = is_undef_freq(current_signal)
|
undef_freq = is_undef_freq(current_signal)
|
||||||
undef_band = is_undef_band(current_signal)
|
undef_band = is_undef_band(current_signal)
|
||||||
if not undef_freq:
|
if not undef_freq:
|
||||||
self.freq_lab.setText(format_numbers(current_signal.at[Signal.INF_FREQ],
|
self.freq_lab.setText(
|
||||||
current_signal.at[Signal.SUP_FREQ])
|
format_numbers(
|
||||||
|
current_signal.at[Signal.INF_FREQ],
|
||||||
|
current_signal.at[Signal.SUP_FREQ]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.freq_lab.setText("Undefined")
|
self.freq_lab.setText("Undefined")
|
||||||
if not undef_band:
|
if not undef_band:
|
||||||
self.band_lab.setText(format_numbers(current_signal.at[Signal.INF_BAND],
|
self.band_lab.setText(
|
||||||
current_signal.at[Signal.SUP_BAND])
|
format_numbers(
|
||||||
|
current_signal.at[Signal.INF_BAND],
|
||||||
|
current_signal.at[Signal.SUP_BAND]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.band_lab.setText("Undefined")
|
self.band_lab.setText("Undefined")
|
||||||
@@ -1183,7 +1265,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.audio_widget.set_audio_player(self.current_signal_name)
|
self.audio_widget.set_audio_player(self.current_signal_name)
|
||||||
else:
|
else:
|
||||||
self.url_button.setEnabled(False)
|
self.url_button.setEnabled(False)
|
||||||
self.url_button.setStyleSheet(f"color: {self.url_button.colors.inactive};")
|
self.url_button.setStyleSheet(
|
||||||
|
f"color: {self.url_button.colors.inactive};"
|
||||||
|
)
|
||||||
self.current_signal_name = ''
|
self.current_signal_name = ''
|
||||||
self.name_lab.setText("No Signal")
|
self.name_lab.setText("No Signal")
|
||||||
self.name_lab.setAlignment(Qt.AlignHCenter)
|
self.name_lab.setAlignment(Qt.AlignHCenter)
|
||||||
@@ -1195,15 +1279,23 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
self.audio_widget.set_audio_player()
|
self.audio_widget.set_audio_player()
|
||||||
|
|
||||||
def display_spectrogram(self):
|
def display_spectrogram(self):
|
||||||
default_pic = os.path.join(self.default_images_folder, Constants.NOT_SELECTED)
|
default_pic = os.path.join(
|
||||||
|
self.default_images_folder,
|
||||||
|
Constants.NOT_SELECTED
|
||||||
|
)
|
||||||
item = self.result_list.currentItem()
|
item = self.result_list.currentItem()
|
||||||
if item:
|
if item:
|
||||||
spectrogram_name = item.text()
|
spectrogram_name = item.text()
|
||||||
path_spectr = os.path.join(Constants.DATA_FOLDER,
|
path_spectr = os.path.join(
|
||||||
|
Constants.DATA_FOLDER,
|
||||||
Constants.SPECTRA_FOLDER,
|
Constants.SPECTRA_FOLDER,
|
||||||
spectrogram_name + Constants.SPECTRA_EXT)
|
spectrogram_name + Constants.SPECTRA_EXT
|
||||||
|
)
|
||||||
if not QFileInfo(path_spectr).exists():
|
if not QFileInfo(path_spectr).exists():
|
||||||
path_spectr = os.path.join(self.default_images_folder, Constants.NOT_AVAILABLE)
|
path_spectr = os.path.join(
|
||||||
|
self.default_images_folder,
|
||||||
|
Constants.NOT_AVAILABLE
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
path_spectr = default_pic
|
path_spectr = default_pic
|
||||||
self.spectrogram.setPixmap(QPixmap(path_spectr))
|
self.spectrogram.setPixmap(QPixmap(path_spectr))
|
||||||
@@ -1247,13 +1339,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def go_to_web_page_signal(self):
|
def go_to_web_page_signal(self):
|
||||||
if self.current_signal_name:
|
if self.current_signal_name:
|
||||||
self.url_button.setStyleSheet(f"color: {self.url_button.colors.clicked}")
|
self.url_button.setStyleSheet(
|
||||||
|
f"color: {self.url_button.colors.clicked}"
|
||||||
|
)
|
||||||
webbrowser.open(self.db.at[self.current_signal_name, Signal.URL])
|
webbrowser.open(self.db.at[self.current_signal_name, Signal.URL])
|
||||||
self.db.at[self.current_signal_name, Signal.WIKI_CLICKED] = True
|
self.db.at[self.current_signal_name, Signal.WIKI_CLICKED] = True
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
|
self.closing = True
|
||||||
if self.download_window.isVisible():
|
if self.download_window.isVisible():
|
||||||
self.download_window.close()
|
self.download_window.close()
|
||||||
|
if self.space_weather_data.is_updating:
|
||||||
|
self.space_weather_data.shutdown_thread()
|
||||||
super().closeEvent(event)
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from pygame import mixer
|
from pygame import mixer
|
||||||
from PyQt5.QtCore import QTimer, pyqtSlot, QObject
|
from PyQt5.QtCore import QTimer, pyqtSlot, QObject
|
||||||
@@ -9,11 +8,9 @@ import qtawesome as qta
|
|||||||
|
|
||||||
|
|
||||||
class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
||||||
"""
|
"""This is the audio player widget. The only public methods are the __init__
|
||||||
This is the audio player widget. The only public methods are the __init__
|
method, set_audio_player, which loads the current file and refresh_btns_colors.
|
||||||
method, set_audio_player, which loads the current file and refresh_btns_colors. Everything else
|
Everything else is managed internally."""
|
||||||
is managed internally.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__time_step = 500 # Milliseconds.
|
__time_step = 500 # Milliseconds.
|
||||||
|
|
||||||
@@ -52,7 +49,9 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def __set_volume(self):
|
def __set_volume(self):
|
||||||
if mixer.get_init():
|
if mixer.get_init():
|
||||||
mixer.music.set_volume(self.__volume.value() / self.__volume.maximum())
|
mixer.music.set_volume(
|
||||||
|
self.__volume.value() / self.__volume.maximum()
|
||||||
|
)
|
||||||
|
|
||||||
def __reset_audio_widget(self):
|
def __reset_audio_widget(self):
|
||||||
if mixer.get_init():
|
if mixer.get_init():
|
||||||
@@ -82,7 +81,11 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
|||||||
def set_audio_player(self, fname = ""):
|
def set_audio_player(self, fname = ""):
|
||||||
self.__first_call = True
|
self.__first_call = True
|
||||||
self.__reset_audio_widget()
|
self.__reset_audio_widget()
|
||||||
full_name = os.path.join(Constants.DATA_FOLDER, Constants.AUDIO_FOLDER, fname + '.ogg')
|
full_name = os.path.join(
|
||||||
|
Constants.DATA_FOLDER,
|
||||||
|
Constants.AUDIO_FOLDER,
|
||||||
|
fname + '.ogg'
|
||||||
|
)
|
||||||
if os.path.exists(full_name):
|
if os.path.exists(full_name):
|
||||||
self.__play.setEnabled(True)
|
self.__play.setEnabled(True)
|
||||||
self.__audio_file = full_name
|
self.__audio_file = full_name
|
||||||
@@ -92,7 +95,9 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
|||||||
if not self.__paused:
|
if not self.__paused:
|
||||||
if self.__first_call:
|
if self.__first_call:
|
||||||
self.__first_call = False
|
self.__first_call = False
|
||||||
mixer.init(frequency = AudioSegment.from_ogg(self.__audio_file).frame_rate,
|
mixer.init(frequency=AudioSegment.from_ogg(
|
||||||
|
self.__audio_file
|
||||||
|
).frame_rate,
|
||||||
buffer=2048)
|
buffer=2048)
|
||||||
mixer.music.load(self.__audio_file)
|
mixer.music.load(self.__audio_file)
|
||||||
self.__set_volume()
|
self.__set_volume()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from PyQt5.QtWidgets import QProgressBar
|
|||||||
from PyQt5.QtCore import Qt, pyqtSignal
|
from PyQt5.QtCore import Qt, pyqtSignal
|
||||||
from constants import Constants
|
from constants import Constants
|
||||||
|
|
||||||
|
|
||||||
class ClickableProgressBar(QProgressBar):
|
class ClickableProgressBar(QProgressBar):
|
||||||
|
|
||||||
clicked = pyqtSignal()
|
clicked = pyqtSignal()
|
||||||
|
|||||||
31
constants.py
31
constants.py
@@ -1,18 +1,22 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
|
||||||
|
|
||||||
class Ftype(object):
|
class Ftype(object):
|
||||||
FREQ = "freq"
|
FREQ = "freq"
|
||||||
BAND = "band"
|
BAND = "band"
|
||||||
|
|
||||||
|
|
||||||
class GfdType(Enum):
|
class GfdType(Enum):
|
||||||
FREQ = auto()
|
FREQ = auto()
|
||||||
LOC = auto()
|
LOC = auto()
|
||||||
|
|
||||||
|
|
||||||
class ChecksumWhat(Enum):
|
class ChecksumWhat(Enum):
|
||||||
FOLDER = auto()
|
FOLDER = auto()
|
||||||
DB = auto()
|
DB = auto()
|
||||||
|
|
||||||
|
|
||||||
class Messages(object):
|
class Messages(object):
|
||||||
DB_UP_TO_DATE = "Already up to date"
|
DB_UP_TO_DATE = "Already up to date"
|
||||||
DB_UP_TO_DATE_MSG = "No newer version to download."
|
DB_UP_TO_DATE_MSG = "No newer version to download."
|
||||||
@@ -27,6 +31,7 @@ class Messages(object):
|
|||||||
BAD_DOWNLOAD = "Something went wrong"
|
BAD_DOWNLOAD = "Something went wrong"
|
||||||
BAD_DOWNLOAD_MSG = "Something went wrong with the downaload.\nCheck your internet connection and try again."
|
BAD_DOWNLOAD_MSG = "Something went wrong with the downaload.\nCheck your internet connection and try again."
|
||||||
|
|
||||||
|
|
||||||
class Signal(object):
|
class Signal(object):
|
||||||
NAME = "name"
|
NAME = "name"
|
||||||
INF_FREQ = "inf_freq"
|
INF_FREQ = "inf_freq"
|
||||||
@@ -42,6 +47,7 @@ class Signal(object):
|
|||||||
ACF = "acf"
|
ACF = "acf"
|
||||||
WIKI_CLICKED = "url_clicked"
|
WIKI_CLICKED = "url_clicked"
|
||||||
|
|
||||||
|
|
||||||
class Database(object):
|
class Database(object):
|
||||||
LINK_LOC = "https://aresvalley.com/Storage/Artemis/Database/data.zip"
|
LINK_LOC = "https://aresvalley.com/Storage/Artemis/Database/data.zip"
|
||||||
LINK_REF = "https://aresvalley.com/Storage/Artemis/Database/data.zip.log"
|
LINK_REF = "https://aresvalley.com/Storage/Artemis/Database/data.zip.log"
|
||||||
@@ -66,25 +72,26 @@ class Database(object):
|
|||||||
Signal.SUP_BAND,
|
Signal.SUP_BAND,
|
||||||
Signal.CATEGORY_CODE,)
|
Signal.CATEGORY_CODE,)
|
||||||
|
|
||||||
|
|
||||||
class Constants(object):
|
class Constants(object):
|
||||||
CLICK_TO_UPDATE_STR = "Click to update"
|
CLICK_TO_UPDATE_STR = "Click to update"
|
||||||
UPDATING_STR = "Updating..."
|
UPDATING_STR = "Updating..."
|
||||||
ACF_DOCS = "https://aresvalley.com/documentation/"
|
ACF_DOCS = "https://aresvalley.com/documentation/"
|
||||||
FORECAST_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt"
|
FORECAST_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt"
|
||||||
FORECAST_PROT = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt"
|
FORECAST_PROT_EL = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt"
|
||||||
FORECAST_AK_IND = "https://services.swpc.noaa.gov/text/wwv.txt"
|
FORECAST_AK_INDEX = "https://services.swpc.noaa.gov/text/wwv.txt"
|
||||||
FORECAST_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt"
|
FORECAST_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt"
|
||||||
FORECAST_G = "https://services.swpc.noaa.gov/text/3-day-forecast.txt"
|
FORECAST_GEO_STORM = "https://services.swpc.noaa.gov/text/3-day-forecast.txt"
|
||||||
FORECAST_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf"
|
FORECAST_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf"
|
||||||
FORECAST_IMG_0 = "http://www.mmmonvhf.de/eme/eme.png"
|
FORECAST_IMGS = ["http://www.mmmonvhf.de/eme/eme.png",
|
||||||
FORECAST_IMG_1 = "http://www.mmmonvhf.de/ms/ms.png"
|
"http://www.mmmonvhf.de/ms/ms.png",
|
||||||
FORECAST_IMG_2 = "http://www.mmmonvhf.de/es/es.png"
|
"http://www.mmmonvhf.de/es/es.png",
|
||||||
FORECAST_IMG_3 = "http://www.mmmonvhf.de/solar/solar.png"
|
"http://www.mmmonvhf.de/solar/solar.png",
|
||||||
FORECAST_IMG_4 = "http://amunters.home.xs4all.nl/eskipstatusNA.gif"
|
"http://amunters.home.xs4all.nl/eskipstatusNA.gif",
|
||||||
FORECAST_IMG_5 = "http://amunters.home.xs4all.nl/aurorastatus.gif"
|
"http://amunters.home.xs4all.nl/aurorastatus.gif",
|
||||||
FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskipstatus.gif"
|
"http://amunters.home.xs4all.nl/eskipstatus.gif",
|
||||||
FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip50status.gif"
|
"http://amunters.home.xs4all.nl/eskip50status.gif",
|
||||||
FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskip70status.gif"
|
"http://amunters.home.xs4all.nl/eskip70status.gif"]
|
||||||
SEARCH_LABEL_IMG = "search_icon.png"
|
SEARCH_LABEL_IMG = "search_icon.png"
|
||||||
VOLUME_LABEL_IMG = "volume.png"
|
VOLUME_LABEL_IMG = "volume.png"
|
||||||
DATA_FOLDER = "Data"
|
DATA_FOLDER = "Data"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from constants import Messages
|
|||||||
|
|
||||||
Ui_Download_window, _ = uic.loadUiType(resource_path("download_db_window.ui"))
|
Ui_Download_window, _ = uic.loadUiType(resource_path("download_db_window.ui"))
|
||||||
|
|
||||||
|
|
||||||
class DownloadWindow(QWidget, Ui_Download_window):
|
class DownloadWindow(QWidget, Ui_Download_window):
|
||||||
|
|
||||||
complete = pyqtSignal()
|
complete = pyqtSignal()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from PyQt5.QtWidgets import QLabel
|
from PyQt5.QtWidgets import QLabel
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
|
||||||
class FixedAspectRatioLabel(QLabel):
|
class FixedAspectRatioLabel(QLabel):
|
||||||
def __init__(self, parent = None):
|
def __init__(self, parent = None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@@ -20,7 +21,9 @@ class FixedAspectRatioLabel(QLabel):
|
|||||||
if self.pixmap:
|
if self.pixmap:
|
||||||
self.setPixmap(
|
self.setPixmap(
|
||||||
self.pixmap.scaled(
|
self.pixmap.scaled(
|
||||||
self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
|
self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def rescale(self, size):
|
def rescale(self, size):
|
||||||
self.resize(size)
|
self.resize(size)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from PyQt5.QtWidgets import QWidget
|
from PyQt5.QtWidgets import QWidget
|
||||||
from PyQt5.QtCore import QSize
|
from PyQt5.QtCore import QSize
|
||||||
|
|
||||||
|
|
||||||
class FixedAspectRatioWidget(QWidget):
|
class FixedAspectRatioWidget(QWidget):
|
||||||
space = 10
|
space = 10
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
|
aiohttp==3.5.4
|
||||||
altgraph==0.16.1
|
altgraph==0.16.1
|
||||||
asn1crypto==0.24.0
|
asn1crypto==0.24.0
|
||||||
|
async-timeout==3.0.1
|
||||||
|
attrs==19.1.0
|
||||||
certifi==2019.3.9
|
certifi==2019.3.9
|
||||||
cffi==1.11.5
|
cffi==1.11.5
|
||||||
|
chardet==3.0.4
|
||||||
cryptography==2.3.1
|
cryptography==2.3.1
|
||||||
Cython==0.29.6
|
Cython==0.29.6
|
||||||
future==0.16.0
|
future==0.16.0
|
||||||
idna==2.7
|
idna==2.7
|
||||||
intel-openmp==2019.0
|
intel-openmp==2019.0
|
||||||
macholib==1.11
|
macholib==1.11
|
||||||
|
multidict==4.5.2
|
||||||
numpy==1.15.2
|
numpy==1.15.2
|
||||||
pandas==0.23.4
|
pandas==0.23.4
|
||||||
pefile==2018.8.8
|
pefile==2018.8.8
|
||||||
@@ -28,3 +33,4 @@ six==1.11.0
|
|||||||
urllib3==1.24
|
urllib3==1.24
|
||||||
win-inet-pton==1.0.1
|
win-inet-pton==1.0.1
|
||||||
wincertstore==0.2
|
wincertstore==0.2
|
||||||
|
yarl==1.3.0
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from PyQt5.QtGui import QPixmap
|
|||||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
||||||
from threads import UpadteSpaceWeatherThread, ThreadStatus
|
from threads import UpadteSpaceWeatherThread, ThreadStatus
|
||||||
|
|
||||||
|
|
||||||
class SpaceWeatherData(QObject):
|
class SpaceWeatherData(QObject):
|
||||||
update_complete = pyqtSignal(bool)
|
update_complete = pyqtSignal(bool)
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ class SpaceWeatherData(QObject):
|
|||||||
self.ak_index = ''
|
self.ak_index = ''
|
||||||
self.sgas = ''
|
self.sgas = ''
|
||||||
self.geo_storm = ''
|
self.geo_storm = ''
|
||||||
self.images = [QPixmap(),
|
self.images = [
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
@@ -20,7 +21,9 @@ class SpaceWeatherData(QObject):
|
|||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap()]
|
QPixmap(),
|
||||||
|
QPixmap()
|
||||||
|
]
|
||||||
self.__update_thread = UpadteSpaceWeatherThread(self)
|
self.__update_thread = UpadteSpaceWeatherThread(self)
|
||||||
self.__update_thread.finished.connect(self.__parse_and_emit_signal)
|
self.__update_thread.finished.connect(self.__parse_and_emit_signal)
|
||||||
|
|
||||||
@@ -46,7 +49,7 @@ class SpaceWeatherData(QObject):
|
|||||||
self.ak_index = ''
|
self.ak_index = ''
|
||||||
self.sgas = ''
|
self.sgas = ''
|
||||||
self.geo_storm = ''
|
self.geo_storm = ''
|
||||||
self.images = [QPixmap(),
|
self.images = [
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
@@ -54,13 +57,18 @@ class SpaceWeatherData(QObject):
|
|||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap(),
|
QPixmap(),
|
||||||
QPixmap()]
|
QPixmap(),
|
||||||
|
QPixmap()
|
||||||
|
]
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def __parse_and_emit_signal(self):
|
def __parse_and_emit_signal(self):
|
||||||
if self.__update_thread.status is not ThreadStatus.OK:
|
|
||||||
status_ok = False
|
status_ok = False
|
||||||
else:
|
if self.__update_thread.status is ThreadStatus.OK:
|
||||||
status_ok = True
|
status_ok = True
|
||||||
self.__parse_data()
|
self.__parse_data()
|
||||||
self.update_complete.emit(status_ok)
|
self.update_complete.emit(status_ok)
|
||||||
|
|
||||||
|
def shutdown_thread(self):
|
||||||
|
self.__update_thread.terminate()
|
||||||
|
self.__update_thread.wait()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from PyQt5.QtWidgets import QLabel
|
from PyQt5.QtWidgets import QLabel
|
||||||
|
|
||||||
|
|
||||||
class SwitchableLabel(QLabel):
|
class SwitchableLabel(QLabel):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|||||||
215
themes.py
215
themes.py
@@ -9,6 +9,7 @@ from constants import Constants
|
|||||||
from switchable_label import SwitchableLabelsIterable
|
from switchable_label import SwitchableLabelsIterable
|
||||||
from utilities import pop_up
|
from utilities import pop_up
|
||||||
|
|
||||||
|
|
||||||
class ThemeConstants(object):
|
class ThemeConstants(object):
|
||||||
FOLDER = "themes"
|
FOLDER = "themes"
|
||||||
EXTENSION = ".qss"
|
EXTENSION = ".qss"
|
||||||
@@ -34,27 +35,41 @@ class Theme(object):
|
|||||||
self.__theme_path = ""
|
self.__theme_path = ""
|
||||||
self.__current_theme = ""
|
self.__current_theme = ""
|
||||||
|
|
||||||
self.__parent.default_images_folder = os.path.join(ThemeConstants.FOLDER,
|
self.__parent.default_images_folder = os.path.join(
|
||||||
|
ThemeConstants.FOLDER,
|
||||||
ThemeConstants.DEFAULT,
|
ThemeConstants.DEFAULT,
|
||||||
ThemeConstants.ICONS_FOLDER)
|
ThemeConstants.ICONS_FOLDER
|
||||||
|
)
|
||||||
|
|
||||||
self.__forecast_labels = SwitchableLabelsIterable(*list(chain(self.__parent.switchable_r_labels,
|
self.__forecast_labels = SwitchableLabelsIterable(
|
||||||
|
*list(
|
||||||
|
chain(
|
||||||
|
self.__parent.switchable_r_labels,
|
||||||
self.__parent.switchable_s_labels,
|
self.__parent.switchable_s_labels,
|
||||||
self.__parent.switchable_g_now_labels,
|
self.__parent.switchable_g_now_labels,
|
||||||
self.__parent.switchable_g_today_labels,
|
self.__parent.switchable_g_today_labels,
|
||||||
self.__parent.k_storm_labels,
|
self.__parent.k_storm_labels,
|
||||||
self.__parent.a_storm_labels,
|
self.__parent.a_storm_labels,
|
||||||
[self.__parent.expected_noise_lbl])))
|
[self.__parent.expected_noise_lbl]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.__forecast_labels.set("switch_on_colors", ThemeConstants.DEFAULT_ON_COLORS)
|
self.__forecast_labels.set(
|
||||||
self.__forecast_labels.set("switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS)
|
"switch_on_colors",
|
||||||
|
ThemeConstants.DEFAULT_ON_COLORS
|
||||||
|
)
|
||||||
|
self.__forecast_labels.set(
|
||||||
|
"switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS
|
||||||
|
)
|
||||||
|
|
||||||
self.__theme_names = {}
|
self.__theme_names = {}
|
||||||
self.__detect_themes()
|
self.__detect_themes()
|
||||||
|
|
||||||
def __refresh_range_labels(self):
|
def __refresh_range_labels(self):
|
||||||
self.__parent.set_acf_interval_label()
|
self.__parent.set_acf_interval_label()
|
||||||
self.__parent.set_band_filter_label(self.__parent.activate_low_band_filter_btn,
|
self.__parent.set_band_filter_label(
|
||||||
|
self.__parent.activate_low_band_filter_btn,
|
||||||
self.__parent.lower_band_spinbox,
|
self.__parent.lower_band_spinbox,
|
||||||
self.__parent.lower_band_filter_unit,
|
self.__parent.lower_band_filter_unit,
|
||||||
self.__parent.lower_band_confidence,
|
self.__parent.lower_band_confidence,
|
||||||
@@ -62,9 +77,11 @@ class Theme(object):
|
|||||||
self.__parent.upper_band_spinbox,
|
self.__parent.upper_band_spinbox,
|
||||||
self.__parent.upper_band_filter_unit,
|
self.__parent.upper_band_filter_unit,
|
||||||
self.__parent.upper_band_confidence,
|
self.__parent.upper_band_confidence,
|
||||||
self.__parent.band_range_lbl)
|
self.__parent.band_range_lbl
|
||||||
|
)
|
||||||
|
|
||||||
self.__parent.set_band_filter_label(self.__parent.activate_low_freq_filter_btn,
|
self.__parent.set_band_filter_label(
|
||||||
|
self.__parent.activate_low_freq_filter_btn,
|
||||||
self.__parent.lower_freq_spinbox,
|
self.__parent.lower_freq_spinbox,
|
||||||
self.__parent.lower_freq_filter_unit,
|
self.__parent.lower_freq_filter_unit,
|
||||||
self.__parent.lower_freq_confidence,
|
self.__parent.lower_freq_confidence,
|
||||||
@@ -72,16 +89,23 @@ class Theme(object):
|
|||||||
self.__parent.upper_freq_spinbox,
|
self.__parent.upper_freq_spinbox,
|
||||||
self.__parent.upper_freq_filter_unit,
|
self.__parent.upper_freq_filter_unit,
|
||||||
self.__parent.upper_freq_confidence,
|
self.__parent.upper_freq_confidence,
|
||||||
self.__parent.freq_range_lbl)
|
self.__parent.freq_range_lbl
|
||||||
|
)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def __apply(self, theme_path):
|
def __apply(self, theme_path):
|
||||||
self.__theme_path = theme_path
|
self.__theme_path = theme_path
|
||||||
if self.__theme_path != self.__current_theme:
|
if self.__theme_path != self.__current_theme:
|
||||||
self.__change()
|
self.__change()
|
||||||
self.__parent.display_specs(self.__parent.result_list.currentItem(), None)
|
self.__parent.display_specs(
|
||||||
|
item=self.__parent.result_list.currentItem(),
|
||||||
|
previous_item=None
|
||||||
|
)
|
||||||
self.__refresh_range_labels()
|
self.__refresh_range_labels()
|
||||||
self.__parent.audio_widget.refresh_btns_colors(self.__parent.active_color, self.__parent.inactive_color)
|
self.__parent.audio_widget.refresh_btns_colors(
|
||||||
|
self.__parent.active_color,
|
||||||
|
self.__parent.inactive_color
|
||||||
|
)
|
||||||
self.__forecast_labels.refresh()
|
self.__forecast_labels.refresh()
|
||||||
|
|
||||||
def __pretty_name(self, bad_name):
|
def __pretty_name(self, bad_name):
|
||||||
@@ -101,16 +125,33 @@ class Theme(object):
|
|||||||
themes.append(relative_folder)
|
themes.append(relative_folder)
|
||||||
for theme_path in themes:
|
for theme_path in themes:
|
||||||
theme_name = '&' + self.__pretty_name(os.path.basename(theme_path))
|
theme_name = '&' + self.__pretty_name(os.path.basename(theme_path))
|
||||||
new_theme = ag.addAction(QAction(theme_name, self.__parent, checkable = True))
|
new_theme = ag.addAction(
|
||||||
|
QAction(
|
||||||
|
theme_name,
|
||||||
|
self.__parent, checkable=True
|
||||||
|
)
|
||||||
|
)
|
||||||
self.__parent.menu_themes.addAction(new_theme)
|
self.__parent.menu_themes.addAction(new_theme)
|
||||||
self.__theme_names[theme_name.lstrip('&')] = new_theme
|
self.__theme_names[theme_name.lstrip('&')] = new_theme
|
||||||
new_theme.triggered.connect(partial(self.__apply, theme_path))
|
new_theme.triggered.connect(partial(self.__apply, theme_path))
|
||||||
|
|
||||||
|
def __is_valid_html_color(self, colors):
|
||||||
|
pattern = "#([a-zA-Z0-9]){6}"
|
||||||
|
match_ok = lambda col: bool(re.match(pattern, col))
|
||||||
|
if isinstance(colors, list):
|
||||||
|
if len(colors) > 1:
|
||||||
|
return all(match_ok(c) for c in colors)
|
||||||
|
else:
|
||||||
|
return match_ok(colors[0])
|
||||||
|
else:
|
||||||
|
return match_ok(colors)
|
||||||
|
|
||||||
def __change(self):
|
def __change(self):
|
||||||
|
theme_name = os.path.basename(self.__theme_path).split('-')[1] + ThemeConstants.EXTENSION
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(
|
with open(
|
||||||
self.__theme_path,
|
os.path.join(self.__theme_path, theme_name), "r"
|
||||||
os.path.basename(self.__theme_path).split('-')[1] + ThemeConstants.EXTENSION), "r") as stylesheet:
|
) as stylesheet:
|
||||||
style = stylesheet.read()
|
style = stylesheet.read()
|
||||||
self.__parent.setStyleSheet(style)
|
self.__parent.setStyleSheet(style)
|
||||||
self.__parent.download_window.setStyleSheet(style)
|
self.__parent.download_window.setStyleSheet(style)
|
||||||
@@ -119,9 +160,11 @@ class Theme(object):
|
|||||||
text=ThemeConstants.MISSING_THEME).show()
|
text=ThemeConstants.MISSING_THEME).show()
|
||||||
else:
|
else:
|
||||||
icons_path = os.path.join(self.__theme_path, ThemeConstants.ICONS_FOLDER)
|
icons_path = os.path.join(self.__theme_path, ThemeConstants.ICONS_FOLDER)
|
||||||
default_icons_path = os.path.join(ThemeConstants.FOLDER,
|
default_icons_path = os.path.join(
|
||||||
|
ThemeConstants.FOLDER,
|
||||||
ThemeConstants.DEFAULT,
|
ThemeConstants.DEFAULT,
|
||||||
ThemeConstants.ICONS_FOLDER)
|
ThemeConstants.ICONS_FOLDER
|
||||||
|
)
|
||||||
|
|
||||||
if os.path.exists(os.path.join(icons_path, Constants.NOT_SELECTED)) and \
|
if os.path.exists(os.path.join(icons_path, Constants.NOT_SELECTED)) and \
|
||||||
os.path.exists(os.path.join(icons_path, Constants.NOT_AVAILABLE)):
|
os.path.exists(os.path.join(icons_path, Constants.NOT_AVAILABLE)):
|
||||||
@@ -129,33 +172,65 @@ class Theme(object):
|
|||||||
else:
|
else:
|
||||||
self.__parent.default_images_folder = default_icons_path
|
self.__parent.default_images_folder = default_icons_path
|
||||||
|
|
||||||
path_to_search_label = os.path.join(icons_path, Constants.SEARCH_LABEL_IMG)
|
path_to_search_label = os.path.join(
|
||||||
default_search_label = os.path.join(default_icons_path, Constants.SEARCH_LABEL_IMG)
|
icons_path,
|
||||||
|
Constants.SEARCH_LABEL_IMG
|
||||||
|
)
|
||||||
|
default_search_label = os.path.join(
|
||||||
|
default_icons_path,
|
||||||
|
Constants.SEARCH_LABEL_IMG
|
||||||
|
)
|
||||||
|
|
||||||
if os.path.exists(path_to_search_label):
|
if os.path.exists(path_to_search_label):
|
||||||
self.__parent.search_label.setPixmap(QPixmap(path_to_search_label))
|
self.__parent.search_label.setPixmap(
|
||||||
self.__parent.modulation_search_label.setPixmap(QPixmap(path_to_search_label))
|
QPixmap(path_to_search_label)
|
||||||
self.__parent.location_search_label.setPixmap(QPixmap(path_to_search_label))
|
)
|
||||||
|
self.__parent.modulation_search_label.setPixmap(
|
||||||
|
QPixmap(path_to_search_label)
|
||||||
|
)
|
||||||
|
self.__parent.location_search_label.setPixmap(
|
||||||
|
QPixmap(path_to_search_label)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.__parent.search_label.setPixmap(QPixmap(default_search_label))
|
self.__parent.search_label.setPixmap(
|
||||||
self.__parent.modulation_search_label.setPixmap(QPixmap(default_search_label))
|
QPixmap(default_search_label)
|
||||||
self.__parent.location_search_label.setPixmap(QPixmap(default_search_label))
|
)
|
||||||
|
self.__parent.modulation_search_label.setPixmap(
|
||||||
|
QPixmap(default_search_label)
|
||||||
|
)
|
||||||
|
self.__parent.location_search_label.setPixmap(
|
||||||
|
QPixmap(default_search_label)
|
||||||
|
)
|
||||||
|
|
||||||
self.__parent.search_label.setScaledContents(True)
|
self.__parent.search_label.setScaledContents(True)
|
||||||
self.__parent.modulation_search_label.setScaledContents(True)
|
self.__parent.modulation_search_label.setScaledContents(True)
|
||||||
self.__parent.location_search_label.setScaledContents(True)
|
self.__parent.location_search_label.setScaledContents(True)
|
||||||
|
|
||||||
path_to_volume_label = os.path.join(icons_path, Constants.VOLUME_LABEL_IMG)
|
path_to_volume_label = os.path.join(
|
||||||
default_volume_label = os.path.join(default_icons_path, Constants.VOLUME_LABEL_IMG)
|
icons_path,
|
||||||
|
Constants.VOLUME_LABEL_IMG
|
||||||
|
)
|
||||||
|
default_volume_label = os.path.join(
|
||||||
|
default_icons_path,
|
||||||
|
Constants.VOLUME_LABEL_IMG
|
||||||
|
)
|
||||||
|
|
||||||
if os.path.exists(path_to_volume_label):
|
if os.path.exists(path_to_volume_label):
|
||||||
self.__parent.volume_label.setPixmap(QPixmap(path_to_volume_label))
|
self.__parent.volume_label.setPixmap(
|
||||||
|
QPixmap(path_to_volume_label)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.__parent.volume_label.setPixmap(QPixmap(default_volume_label))
|
self.__parent.volume_label.setPixmap(
|
||||||
|
QPixmap(default_volume_label)
|
||||||
|
)
|
||||||
|
|
||||||
self.__parent.volume_label.setScaledContents(True)
|
self.__parent.volume_label.setScaledContents(True)
|
||||||
|
|
||||||
path_to_colors = os.path.join(self.__theme_path, ThemeConstants.COLORS)
|
path_to_colors = os.path.join(
|
||||||
|
self.__theme_path,
|
||||||
|
ThemeConstants.COLORS
|
||||||
|
)
|
||||||
|
|
||||||
active_color_ok = False
|
active_color_ok = False
|
||||||
inactive_color_ok = False
|
inactive_color_ok = False
|
||||||
switch_on_color_ok = False
|
switch_on_color_ok = False
|
||||||
@@ -163,57 +238,78 @@ class Theme(object):
|
|||||||
text_color_ok = False
|
text_color_ok = False
|
||||||
|
|
||||||
if os.path.exists(path_to_colors):
|
if os.path.exists(path_to_colors):
|
||||||
is_valid_html_color = lambda colors : all([bool(re.match("#([a-zA-Z0-9]){6}", color)) for color in colors])
|
|
||||||
with open(path_to_colors, "r") as colors_file:
|
with open(path_to_colors, "r") as colors_file:
|
||||||
for line in colors_file:
|
for line in colors_file:
|
||||||
if ThemeConstants.COLOR_SEPARATOR in line:
|
if ThemeConstants.COLOR_SEPARATOR in line:
|
||||||
quality, color = line.split(ThemeConstants.COLOR_SEPARATOR)
|
quality, color = line.split(ThemeConstants.COLOR_SEPARATOR)
|
||||||
color = color.rstrip()
|
color = color.rstrip()
|
||||||
|
color_len = 1
|
||||||
if ',' in color:
|
if ',' in color:
|
||||||
color = [c.rstrip().lstrip() for c in color.split(',')]
|
color = [c.strip() for c in color.split(',')]
|
||||||
else:
|
color_len = len(color)
|
||||||
color = [color]
|
if self.__is_valid_html_color(color):
|
||||||
if len(color) > 2:
|
if color_len == 1:
|
||||||
break
|
|
||||||
if is_valid_html_color(color):
|
|
||||||
if quality.lower() == Constants.ACTIVE:
|
if quality.lower() == Constants.ACTIVE:
|
||||||
self.__parent.active_color = color[0]
|
self.__parent.active_color = color
|
||||||
active_color_ok = True
|
active_color_ok = True
|
||||||
if quality.lower() == Constants.INACTIVE:
|
if quality.lower() == Constants.INACTIVE:
|
||||||
self.__parent.inactive_color = color[0]
|
self.__parent.inactive_color = color
|
||||||
inactive_color_ok = True
|
inactive_color_ok = True
|
||||||
if len(color) == 2:
|
|
||||||
if quality.lower() == Constants.LABEL_ON_COLOR:
|
|
||||||
switch_on_color_ok = True
|
|
||||||
self.__forecast_labels.set("switch_on_colors", color)
|
|
||||||
if quality.lower() == Constants.LABEL_OFF_COLOR:
|
|
||||||
switch_off_color_ok = True
|
|
||||||
self.__forecast_labels.set("switch_off_colors", color)
|
|
||||||
if quality.lower() == Constants.TEXT_COLOR:
|
if quality.lower() == Constants.TEXT_COLOR:
|
||||||
text_color_ok = True
|
text_color_ok = True
|
||||||
self.__forecast_labels.set("text_color", color[0])
|
self.__forecast_labels.set(
|
||||||
|
"text_color",
|
||||||
|
color
|
||||||
|
)
|
||||||
|
if color_len == 2:
|
||||||
|
if quality.lower() == Constants.LABEL_ON_COLOR:
|
||||||
|
switch_on_color_ok = True
|
||||||
|
self.__forecast_labels.set(
|
||||||
|
"switch_on_colors",
|
||||||
|
color
|
||||||
|
)
|
||||||
|
if quality.lower() == Constants.LABEL_OFF_COLOR:
|
||||||
|
switch_off_color_ok = True
|
||||||
|
self.__forecast_labels.set(
|
||||||
|
"switch_off_colors",
|
||||||
|
color
|
||||||
|
)
|
||||||
|
|
||||||
if not (active_color_ok and inactive_color_ok):
|
if not (active_color_ok and inactive_color_ok):
|
||||||
self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR
|
self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR
|
||||||
self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR
|
self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR
|
||||||
|
|
||||||
if not (switch_on_color_ok and switch_off_color_ok):
|
if not (switch_on_color_ok and switch_off_color_ok):
|
||||||
self.__forecast_labels.set("switch_on_colors", ThemeConstants.DEFAULT_ON_COLORS)
|
self.__forecast_labels.set(
|
||||||
self.__forecast_labels.set("switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS)
|
"switch_on_colors",
|
||||||
|
ThemeConstants.DEFAULT_ON_COLORS
|
||||||
|
)
|
||||||
|
self.__forecast_labels.set(
|
||||||
|
"switch_off_colors",
|
||||||
|
ThemeConstants.DEFAULT_OFF_COLORS
|
||||||
|
)
|
||||||
|
|
||||||
if not text_color_ok:
|
if not text_color_ok:
|
||||||
self.__forecast_labels.set("text_color", ThemeConstants.DEFAULT_TEXT_COLOR)
|
self.__forecast_labels.set(
|
||||||
|
"text_color",
|
||||||
|
ThemeConstants.DEFAULT_TEXT_COLOR
|
||||||
|
)
|
||||||
self.__current_theme = self.__theme_path
|
self.__current_theme = self.__theme_path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(ThemeConstants.FOLDER,
|
with open(os.path.join(
|
||||||
ThemeConstants.CURRENT), "w") as current_theme:
|
ThemeConstants.FOLDER,
|
||||||
|
ThemeConstants.CURRENT
|
||||||
|
), "w") as current_theme:
|
||||||
current_theme.write(self.__theme_path)
|
current_theme.write(self.__theme_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
current_theme_file = os.path.join(ThemeConstants.FOLDER, ThemeConstants.CURRENT)
|
current_theme_file = os.path.join(
|
||||||
|
ThemeConstants.FOLDER,
|
||||||
|
ThemeConstants.CURRENT
|
||||||
|
)
|
||||||
if os.path.exists(current_theme_file):
|
if os.path.exists(current_theme_file):
|
||||||
with open(current_theme_file, "r") as current_theme_path:
|
with open(current_theme_file, "r") as current_theme_path:
|
||||||
theme_path = current_theme_path.read()
|
theme_path = current_theme_path.read()
|
||||||
@@ -221,5 +317,12 @@ class Theme(object):
|
|||||||
self.__theme_names[theme_name].setChecked(True)
|
self.__theme_names[theme_name].setChecked(True)
|
||||||
self.__apply(theme_path)
|
self.__apply(theme_path)
|
||||||
else:
|
else:
|
||||||
self.__theme_names[self.__pretty_name(ThemeConstants.DEFAULT)].setChecked(True)
|
self.__theme_names[
|
||||||
self.__apply(os.path.join(ThemeConstants.FOLDER, ThemeConstants.DEFAULT))
|
self.__pretty_name(ThemeConstants.DEFAULT)
|
||||||
|
].setChecked(True)
|
||||||
|
self.__apply(
|
||||||
|
os.path.join(
|
||||||
|
ThemeConstants.FOLDER,
|
||||||
|
ThemeConstants.DEFAULT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
105
threads.py
105
threads.py
@@ -1,13 +1,16 @@
|
|||||||
|
import asyncio
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import os.path
|
import os.path
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
import urllib3
|
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
import aiohttp
|
||||||
|
import urllib3
|
||||||
from PyQt5.QtCore import QThread
|
from PyQt5.QtCore import QThread
|
||||||
from constants import Constants, Database, ChecksumWhat
|
from constants import Constants, Database, ChecksumWhat
|
||||||
from utilities import checksum_ok
|
from utilities import checksum_ok
|
||||||
|
|
||||||
|
|
||||||
class ThreadStatus(Enum):
|
class ThreadStatus(Enum):
|
||||||
OK = auto()
|
OK = auto()
|
||||||
NO_CONNECTION_ERR = auto()
|
NO_CONNECTION_ERR = auto()
|
||||||
@@ -15,38 +18,42 @@ class ThreadStatus(Enum):
|
|||||||
BAD_DOWNLOAD_ERR = auto()
|
BAD_DOWNLOAD_ERR = auto()
|
||||||
UNDEFINED = auto()
|
UNDEFINED = auto()
|
||||||
|
|
||||||
class DownloadThread(QThread):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.__status = ThreadStatus.UNDEFINED
|
|
||||||
self.reason = 0
|
|
||||||
|
|
||||||
@property
|
class _BaseDownloadThread(QThread):
|
||||||
def status(self):
|
def __init__(self, parent=None):
|
||||||
return self.__status
|
super().__init__(parent)
|
||||||
|
self.status = ThreadStatus.UNDEFINED
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.terminate()
|
self.terminate()
|
||||||
self.wait()
|
self.wait()
|
||||||
|
super().__del__()
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadThread(_BaseDownloadThread):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.reason = 0
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
self.status = ThreadStatus.UNDEFINED
|
||||||
try:
|
try:
|
||||||
db = urllib3.PoolManager().request('GET', Database.LINK_LOC)
|
db = urllib3.PoolManager().request('GET', Database.LINK_LOC)
|
||||||
except urllib3.exceptions.MaxRetryError: # No internet connection.
|
except urllib3.exceptions.MaxRetryError: # No internet connection.
|
||||||
self.__status = ThreadStatus.NO_CONNECTION_ERR
|
self.status = ThreadStatus.NO_CONNECTION_ERR
|
||||||
return
|
return
|
||||||
if db.status != 200:
|
if db.status != 200:
|
||||||
self.reason = db.reason
|
self.reason = db.reason
|
||||||
self.__status = ThreadStatus.BAD_DOWNLOAD_ERR
|
self.status = ThreadStatus.BAD_DOWNLOAD_ERR
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
is_checksum_ok = checksum_ok(db.data, ChecksumWhat.FOLDER)
|
is_checksum_ok = checksum_ok(db.data, ChecksumWhat.FOLDER)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__status = ThreadStatus.NO_CONNECTION_ERR
|
self.status = ThreadStatus.NO_CONNECTION_ERR
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if not is_checksum_ok:
|
if not is_checksum_ok:
|
||||||
self.__status = ThreadStatus.BAD_DOWNLOAD_ERR
|
self.status = ThreadStatus.BAD_DOWNLOAD_ERR
|
||||||
return
|
return
|
||||||
if os.path.exists(Constants.DATA_FOLDER):
|
if os.path.exists(Constants.DATA_FOLDER):
|
||||||
rmtree(Constants.DATA_FOLDER)
|
rmtree(Constants.DATA_FOLDER)
|
||||||
@@ -54,43 +61,55 @@ class DownloadThread(QThread):
|
|||||||
with ZipFile(BytesIO(db.data)) as zipped:
|
with ZipFile(BytesIO(db.data)) as zipped:
|
||||||
zipped.extractall()
|
zipped.extractall()
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__status = ThreadStatus.UNKNOWN_ERR
|
self.status = ThreadStatus.UNKNOWN_ERR
|
||||||
else:
|
else:
|
||||||
self.__status = ThreadStatus.OK
|
self.status = ThreadStatus.OK
|
||||||
|
|
||||||
|
|
||||||
class UpadteSpaceWeatherThread(QThread):
|
class UpadteSpaceWeatherThread(_BaseDownloadThread):
|
||||||
|
|
||||||
|
__properties = ("xray", "prot_el", "ak_index", "sgas", "geo_storm")
|
||||||
|
|
||||||
def __init__(self, space_weather_data):
|
def __init__(self, space_weather_data):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.__status = ThreadStatus.UNDEFINED
|
|
||||||
self.__space_weather_data = space_weather_data
|
self.__space_weather_data = space_weather_data
|
||||||
|
|
||||||
@property
|
async def __download_resource(self, session, link):
|
||||||
def status(self):
|
resp = await session.get(link)
|
||||||
return self.__status
|
return await resp.read()
|
||||||
|
|
||||||
def __del__(self):
|
async def __download_property(self, session, property_name):
|
||||||
self.terminate()
|
link = getattr(Constants, "FORECAST_" + property_name.upper())
|
||||||
self.wait()
|
data = await self.__download_resource(session, link)
|
||||||
|
setattr(self.__space_weather_data, property_name, str(data, 'utf-8'))
|
||||||
|
|
||||||
|
async def __download_image(self, session, n):
|
||||||
|
im = await self.__download_resource(session, Constants.FORECAST_IMGS[n])
|
||||||
|
self.__space_weather_data.images[n].loadFromData(im)
|
||||||
|
|
||||||
|
async def __download_resources(self, *links):
|
||||||
|
session = aiohttp.ClientSession()
|
||||||
|
try:
|
||||||
|
t = []
|
||||||
|
for p in self.__properties:
|
||||||
|
t.append(
|
||||||
|
asyncio.create_task(self.__download_property(session, p))
|
||||||
|
)
|
||||||
|
|
||||||
|
tot_images = range(len(Constants.FORECAST_IMGS))
|
||||||
|
t1 = []
|
||||||
|
for im_number in tot_images:
|
||||||
|
t1.append(
|
||||||
|
asyncio.create_task(self.__download_image(session, im_number))
|
||||||
|
)
|
||||||
|
await asyncio.gather(*t, *t1)
|
||||||
|
except Exception:
|
||||||
|
self.status = ThreadStatus.UNKNOWN_ERR
|
||||||
|
else:
|
||||||
|
self.status = ThreadStatus.OK
|
||||||
|
finally:
|
||||||
|
await session.close()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
get_request_data = lambda link: urllib3.PoolManager().request('GET', link).data
|
self.status = ThreadStatus.UNDEFINED
|
||||||
try:
|
asyncio.run(self.__download_resources())
|
||||||
self.__space_weather_data.xray = str(get_request_data(Constants.FORECAST_XRAY), 'utf-8')
|
|
||||||
self.__space_weather_data.prot_el = str(get_request_data(Constants.FORECAST_PROT), 'utf-8')
|
|
||||||
self.__space_weather_data.ak_index = str(get_request_data(Constants.FORECAST_AK_IND), 'utf-8')
|
|
||||||
self.__space_weather_data.sgas = str(get_request_data(Constants.FORECAST_SGAS), 'utf-8')
|
|
||||||
self.__space_weather_data.geo_storm = str(get_request_data(Constants.FORECAST_G), 'utf-8')
|
|
||||||
self.__space_weather_data.images[0].loadFromData(get_request_data(Constants.FORECAST_IMG_0))
|
|
||||||
self.__space_weather_data.images[1].loadFromData(get_request_data(Constants.FORECAST_IMG_1))
|
|
||||||
self.__space_weather_data.images[2].loadFromData(get_request_data(Constants.FORECAST_IMG_2))
|
|
||||||
self.__space_weather_data.images[3].loadFromData(get_request_data(Constants.FORECAST_IMG_3))
|
|
||||||
self.__space_weather_data.images[4].loadFromData(get_request_data(Constants.FORECAST_IMG_4))
|
|
||||||
self.__space_weather_data.images[5].loadFromData(get_request_data(Constants.FORECAST_IMG_5))
|
|
||||||
self.__space_weather_data.images[6].loadFromData(get_request_data(Constants.FORECAST_IMG_6))
|
|
||||||
self.__space_weather_data.images[7].loadFromData(get_request_data(Constants.FORECAST_IMG_7))
|
|
||||||
self.__space_weather_data.images[8].loadFromData(get_request_data(Constants.FORECAST_IMG_8))
|
|
||||||
except Exception:
|
|
||||||
self.__status = ThreadStatus.UNKNOWN_ERR
|
|
||||||
else:
|
|
||||||
self.__status = ThreadStatus.OK
|
|
||||||
|
|||||||
@@ -48,14 +48,16 @@ def checksum_ok(data, what):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Wrong entry name.")
|
raise ValueError("Wrong entry name.")
|
||||||
try:
|
try:
|
||||||
reference = read_csv(Database.LINK_REF,
|
reference = read_csv(
|
||||||
delimiter = Database.DELIMITER).iat[-1, n]
|
Database.LINK_REF,
|
||||||
|
delimiter=Database.DELIMITER
|
||||||
|
).iat[-1, n]
|
||||||
except Exception:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
return code.hexdigest() == reference
|
return code.hexdigest() == reference
|
||||||
|
|
||||||
def connect_events_to_func(events_to_connect, fun_to_connect, fun_args):
|
def connect_events_to_func(events_to_connect, fun_to_connect, fun_args):
|
||||||
if fun_args:
|
if fun_args is not None:
|
||||||
for event in events_to_connect:
|
for event in events_to_connect:
|
||||||
event.connect(partial(fun_to_connect, *fun_args))
|
event.connect(partial(fun_to_connect, *fun_args))
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user