Merge branch 'async_download'

This commit is contained in:
alessandro90
2019-05-01 19:50:20 +02:00
14 changed files with 716 additions and 462 deletions

View File

@@ -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()
@@ -140,20 +157,20 @@ class Artemis(QMainWindow, Ui_MainWindow):
) )
connect_events_to_func( connect_events_to_func(
events_to_connect = [self.lower_freq_spinbox.valueChanged, events_to_connect=[self.lower_freq_spinbox.valueChanged,
self.upper_freq_spinbox.valueChanged, self.upper_freq_spinbox.valueChanged,
self.lower_freq_filter_unit.currentTextChanged, self.lower_freq_filter_unit.currentTextChanged,
self.upper_freq_filter_unit.currentTextChanged, self.upper_freq_filter_unit.currentTextChanged,
self.activate_low_freq_filter_btn.toggled], self.activate_low_freq_filter_btn.toggled],
fun_to_connect = self.set_min_value_upper_limit, fun_to_connect=self.set_min_value_upper_limit,
fun_args = [self.lower_freq_filter_unit, fun_args=[self.lower_freq_filter_unit,
self.lower_freq_spinbox, self.lower_freq_spinbox,
self.upper_freq_filter_unit, self.upper_freq_filter_unit,
self.upper_freq_spinbox] self.upper_freq_spinbox]
) )
connect_events_to_func( connect_events_to_func(
events_to_connect = [self.lower_freq_spinbox.valueChanged, events_to_connect=[self.lower_freq_spinbox.valueChanged,
self.upper_freq_spinbox.valueChanged, self.upper_freq_spinbox.valueChanged,
self.lower_freq_filter_unit.currentTextChanged, self.lower_freq_filter_unit.currentTextChanged,
self.upper_freq_filter_unit.currentTextChanged, self.upper_freq_filter_unit.currentTextChanged,
@@ -161,8 +178,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
self.activate_up_freq_filter_btn.clicked, self.activate_up_freq_filter_btn.clicked,
self.lower_freq_confidence.valueChanged, self.lower_freq_confidence.valueChanged,
self.upper_freq_confidence.valueChanged], self.upper_freq_confidence.valueChanged],
fun_to_connect = self.set_band_filter_label, fun_to_connect=self.set_band_filter_label,
fun_args = [self.activate_low_freq_filter_btn, fun_args=[self.activate_low_freq_filter_btn,
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,
@@ -191,45 +208,47 @@ 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.
connect_events_to_func( connect_events_to_func(
events_to_connect = [self.lower_band_spinbox.valueChanged, events_to_connect=[self.lower_band_spinbox.valueChanged,
self.upper_band_spinbox.valueChanged, self.upper_band_spinbox.valueChanged,
self.lower_band_filter_unit.currentTextChanged, self.lower_band_filter_unit.currentTextChanged,
self.upper_band_filter_unit.currentTextChanged, self.upper_band_filter_unit.currentTextChanged,
self.activate_low_band_filter_btn.toggled], self.activate_low_band_filter_btn.toggled],
fun_to_connect = self.set_min_value_upper_limit, fun_to_connect = self.set_min_value_upper_limit,
fun_args = [self.lower_band_filter_unit, fun_args=[self.lower_band_filter_unit,
self.lower_band_spinbox, self.lower_band_spinbox,
self.upper_band_filter_unit, self.upper_band_filter_unit,
self.upper_band_spinbox] self.upper_band_spinbox]
) )
connect_events_to_func( connect_events_to_func(
events_to_connect = [self.lower_band_spinbox.valueChanged, events_to_connect=[self.lower_band_spinbox.valueChanged,
self.upper_band_spinbox.valueChanged, self.upper_band_spinbox.valueChanged,
self.lower_band_filter_unit.currentTextChanged, self.lower_band_filter_unit.currentTextChanged,
self.upper_band_filter_unit.currentTextChanged, self.upper_band_filter_unit.currentTextChanged,
@@ -237,8 +256,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
self.activate_up_band_filter_btn.clicked, self.activate_up_band_filter_btn.clicked,
self.lower_band_confidence.valueChanged, self.lower_band_confidence.valueChanged,
self.upper_band_confidence.valueChanged], self.upper_band_confidence.valueChanged],
fun_to_connect = self.set_band_filter_label, fun_to_connect=self.set_band_filter_label,
fun_args = [self.activate_low_band_filter_btn, fun_args=[self.activate_low_band_filter_btn,
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,
@@ -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,23 +416,34 @@ 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,
fun_to_connect = self.set_acf_interval_label, self.acf_confidence.valueChanged],
fun_args = None fun_to_connect=self.set_acf_interval_label,
fun_args=None
) )
# GFD # GFD
@@ -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,16 +648,18 @@ 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()
@pyqtSlot() @pyqtSlot()
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()
@@ -719,17 +778,17 @@ class Artemis(QMainWindow, Ui_MainWindow):
try: try:
is_checksum_ok = checksum_ok(db, ChecksumWhat.DB) is_checksum_ok = checksum_ok(db, ChecksumWhat.DB)
except Exception: except Exception:
pop_up(self, title = Messages.NO_CONNECTION, pop_up(self, title=Messages.NO_CONNECTION,
text = Messages.NO_CONNECTION_MSG).show() text=Messages.NO_CONNECTION_MSG).show()
else: else:
if not is_checksum_ok: if not is_checksum_ok:
self.download_db() self.download_db()
else: else:
answer = pop_up(self, title = Messages.DB_UP_TO_DATE, answer = pop_up(self, title=Messages.DB_UP_TO_DATE,
text = Messages.DB_UP_TO_DATE_MSG, text=Messages.DB_UP_TO_DATE_MSG,
informative_text = Messages.DOWNLOAD_ANYWAY_QUESTION, informative_text=Messages.DOWNLOAD_ANYWAY_QUESTION,
is_question = True, is_question=True,
default_btn = QMessageBox.No).exec() default_btn=QMessageBox.No).exec()
if answer == QMessageBox.Yes: if answer == QMessageBox.Yes:
self.download_db() self.download_db()
@@ -742,27 +801,27 @@ class Artemis(QMainWindow, Ui_MainWindow):
with open(db_path, "rb") as file_db: with open(db_path, "rb") as file_db:
db = file_db.read() db = file_db.read()
except Exception: except Exception:
answer = pop_up(self, title = Messages.NO_DB, answer = pop_up(self, title=Messages.NO_DB,
text = Messages.NO_DB_AVAIL, text=Messages.NO_DB_AVAIL,
informative_text = Messages.DOWNLOAD_NOW_QUESTION, informative_text=Messages.DOWNLOAD_NOW_QUESTION,
is_question = True).exec() is_question=True).exec()
if answer == QMessageBox.Yes: if answer == QMessageBox.Yes:
self.download_db() self.download_db()
else: else:
try: try:
is_checksum_ok = checksum_ok(db, ChecksumWhat.DB) is_checksum_ok = checksum_ok(db, ChecksumWhat.DB)
except Exception: except Exception:
pop_up(self, title = Messages.NO_CONNECTION, pop_up(self, title=Messages.NO_CONNECTION,
text = Messages.NO_CONNECTION_MSG).show() text=Messages.NO_CONNECTION_MSG).show()
else: else:
if is_checksum_ok: if is_checksum_ok:
pop_up(self, title = Messages.DB_UP_TO_DATE, pop_up(self, title=Messages.DB_UP_TO_DATE,
text = Messages.DB_UP_TO_DATE_MSG).show() text=Messages.DB_UP_TO_DATE_MSG).show()
else: else:
answer = pop_up(self, title = Messages.DB_NEW_VER, answer = pop_up(self, title=Messages.DB_NEW_VER,
text = Messages.DB_NEW_VER_MSG, text=Messages.DB_NEW_VER_MSG,
informative_text = Messages.DOWNLOAD_NOW_QUESTION, informative_text=Messages.DOWNLOAD_NOW_QUESTION,
is_question = True).exec() is_question=True).exec()
if answer == QMessageBox.Yes: if answer == QMessageBox.Yes:
self.download_db() self.download_db()
@@ -776,23 +835,23 @@ class Artemis(QMainWindow, Ui_MainWindow):
names = Database.NAMES names = Database.NAMES
try: try:
self.db = read_csv(os.path.join(Constants.DATA_FOLDER, Database.NAME), self.db = read_csv(os.path.join(Constants.DATA_FOLDER, Database.NAME),
sep = Database.DELIMITER, sep=Database.DELIMITER,
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,
text = Messages.NO_DB_AVAIL, text=Messages.NO_DB_AVAIL,
informative_text = Messages.DOWNLOAD_NOW_QUESTION, informative_text=Messages.DOWNLOAD_NOW_QUESTION,
is_question = True).exec() is_question=True).exec()
if answer == QMessageBox.Yes: if answer == QMessageBox.Yes:
self.download_db() self.download_db()
else: else:
self.signal_names = self.db.index self.signal_names = self.db.index
self.total_signals = len(self.signal_names) self.total_signals = len(self.signal_names)
self.db.fillna(Constants.UNKNOWN, inplace = True) self.db.fillna(Constants.UNKNOWN, inplace=True)
self.db[Signal.WIKI_CLICKED] = False self.db[Signal.WIKI_CLICKED] = False
self.update_status_tip(self.total_signals) self.update_status_tip(self.total_signals)
self.result_list.clear() self.result_list.clear()
@@ -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)

View File

@@ -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.
@@ -40,19 +37,21 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject
def refresh_btns_colors(self, active_color, inactive_color): def refresh_btns_colors(self, active_color, inactive_color):
self.__play.setIcon(qta.icon('fa5.play-circle', self.__play.setIcon(qta.icon('fa5.play-circle',
color = active_color, color=active_color,
color_disabled = inactive_color)) color_disabled=inactive_color))
self.__pause.setIcon(qta.icon('fa5.pause-circle', self.__pause.setIcon(qta.icon('fa5.pause-circle',
color = active_color, color=active_color,
color_disabled = inactive_color)) color_disabled=inactive_color))
self.__stop.setIcon(qta.icon('fa5.stop-circle', self.__stop.setIcon(qta.icon('fa5.stop-circle',
color = active_color, color=active_color,
color_disabled = inactive_color)) color_disabled=inactive_color))
@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,8 +95,10 @@ 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(
buffer = 2048) self.__audio_file
).frame_rate,
buffer=2048)
mixer.music.load(self.__audio_file) mixer.music.load(self.__audio_file)
self.__set_volume() self.__set_volume()
self.__set_max_progress_bar() self.__set_max_progress_bar()

View File

@@ -2,11 +2,12 @@ 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()
def __init__(self, parent = None): def __init__(self, parent=None):
self.__text = '' self.__text = ''
super().__init__(parent) super().__init__(parent)

View File

@@ -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"

View File

@@ -2,7 +2,7 @@ from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
class DoubleTextButton(QPushButton): class DoubleTextButton(QPushButton):
def __init__(self, parent = None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.clicked.connect(self.__manage_click) self.clicked.connect(self.__manage_click)
@@ -10,11 +10,11 @@ class DoubleTextButton(QPushButton):
self.__text_a = text_a self.__text_a = text_a
self.__text_b = text_b self.__text_b = text_b
def set_slave_filters(self, simple_ones = None, def set_slave_filters(self, simple_ones=None,
radio_1 = None, radio_1=None,
ruled_by_radio_1 = None, ruled_by_radio_1=None,
radio_2 = None, radio_2=None,
ruled_by_radio_2 = None): ruled_by_radio_2=None):
self.__simple_ones = simple_ones self.__simple_ones = simple_ones
self.__ruled_by_radio_1 = ruled_by_radio_1 self.__ruled_by_radio_1 = ruled_by_radio_1
self.__radio_1 = radio_1 self.__radio_1 = radio_1

View File

@@ -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()
@@ -22,13 +23,13 @@ class DownloadWindow(QWidget, Ui_Download_window):
# Qt.WindowStaysOnTopHint # Qt.WindowStaysOnTopHint
) )
self.no_internet_msg = pop_up(self, title = Messages.NO_CONNECTION, self.no_internet_msg = pop_up(self, title=Messages.NO_CONNECTION,
text = Messages.NO_CONNECTION_MSG, text=Messages.NO_CONNECTION_MSG,
connection = self.close) connection=self.close)
self.bad_db_download_msg = pop_up(self, title = Messages.BAD_DOWNLOAD, self.bad_db_download_msg = pop_up(self, title=Messages.BAD_DOWNLOAD,
text = Messages.BAD_DOWNLOAD_MSG, text=Messages.BAD_DOWNLOAD_MSG,
connection = self.close) connection=self.close)
self.download_thread = DownloadThread() self.download_thread = DownloadThread()
self.download_thread.finished.connect(self.wait_close) self.download_thread.finished.connect(self.wait_close)

View File

@@ -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)

View File

@@ -1,9 +1,10 @@
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):
super().__init__(parent) super().__init__(parent)
self.labels = [] self.labels = []

View File

@@ -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

View File

@@ -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)
@@ -33,7 +36,7 @@ class SpaceWeatherData(QObject):
self.__update_thread.start() self.__update_thread.start()
def __parse_data(self): def __parse_data(self):
double_split = lambda string : [i.split() for i in string.splitlines()] double_split = lambda string: [i.split() for i in string.splitlines()]
self.xray = double_split(self.xray) self.xray = double_split(self.xray)
self.prot_el = double_split(self.prot_el) self.prot_el = double_split(self.prot_el)
self.ak_index = double_split(self.ak_index) self.ak_index = double_split(self.ak_index)
@@ -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()

View File

@@ -1,7 +1,8 @@
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)
self.switch_on_colors = () self.switch_on_colors = ()
self.switch_off_colors = () self.switch_off_colors = ()

221
themes.py
View File

@@ -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):
@@ -93,7 +117,7 @@ class Theme(object):
def __detect_themes(self): def __detect_themes(self):
themes = [] themes = []
ag = QActionGroup(self.__parent, exclusive = True) ag = QActionGroup(self.__parent, exclusive=True)
for theme_folder in os.listdir(ThemeConstants.FOLDER): for theme_folder in os.listdir(ThemeConstants.FOLDER):
relative_folder = os.path.join(ThemeConstants.FOLDER, theme_folder) relative_folder = os.path.join(ThemeConstants.FOLDER, theme_folder)
if os.path.isdir(os.path.abspath(relative_folder)): if os.path.isdir(os.path.abspath(relative_folder)):
@@ -101,27 +125,46 @@ 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)
except FileNotFoundError: except FileNotFoundError:
pop_up(self.__parent, title = ThemeConstants.THEME_NOT_FOUND, pop_up(self.__parent, title=ThemeConstants.THEME_NOT_FOUND,
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
)
)

View File

@@ -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

View File

@@ -21,10 +21,10 @@ def uncheck_and_emit(button):
button.clicked.emit() button.clicked.emit()
def pop_up(cls, title, text, def pop_up(cls, title, text,
informative_text = None, informative_text=None,
connection = None, connection=None,
is_question = False, is_question=False,
default_btn = QMessageBox.Yes): default_btn=QMessageBox.Yes):
msg = QMessageBox(cls) msg = QMessageBox(cls)
msg.setWindowTitle(title) msg.setWindowTitle(title)
msg.setText(text) msg.setText(text)
@@ -48,21 +48,23 @@ 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:
for event in events_to_connect: for event in events_to_connect:
event.connect(fun_to_connect) event.connect(fun_to_connect)
def filters_limit(spinbox, filter_unit, confidence, sign = 1): def filters_limit(spinbox, filter_unit, confidence, sign=1):
band_filter = spinbox.value() * Constants.CONVERSION_FACTORS[filter_unit.currentText()] band_filter = spinbox.value() * Constants.CONVERSION_FACTORS[filter_unit.currentText()]
return band_filter + sign * (confidence.value() * band_filter) // 100 return band_filter + sign * (confidence.value() * band_filter) // 100