Merge branch 'async_download'
This commit is contained in:
351
artemis.py
351
artemis.py
@@ -6,6 +6,7 @@ import sys
|
||||
from time import sleep
|
||||
|
||||
from pandas import read_csv
|
||||
|
||||
from PyQt5.QtWidgets import (QMainWindow,
|
||||
QApplication,
|
||||
qApp,
|
||||
@@ -42,7 +43,8 @@ from utilities import (checksum_ok,
|
||||
format_numbers,
|
||||
resource_path,)
|
||||
|
||||
# import icon_rc
|
||||
import icon_rc
|
||||
|
||||
|
||||
qt_creator_file = resource_path("artemis.ui")
|
||||
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
|
||||
@@ -53,6 +55,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
self.set_initial_size()
|
||||
self.closing = False
|
||||
self.download_window = DownloadWindow()
|
||||
self.download_window.complete.connect(self.show_downloaded_signals)
|
||||
self.actionExit.triggered.connect(qApp.quit)
|
||||
@@ -62,35 +65,44 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.current_signal_name = ''
|
||||
self.signal_names = []
|
||||
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.r2_now_lbl,
|
||||
self.r3_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.s2_now_lbl,
|
||||
self.s3_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.g2_now_lbl,
|
||||
self.g3_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.g2_today_lbl,
|
||||
self.g3_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_sev_storm_lbl,
|
||||
self.k_maj_storm_lbl,
|
||||
@@ -99,16 +111,20 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.k_unsettled_lbl,
|
||||
self.k_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_min_storm_lbl,
|
||||
self.a_active_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_2,
|
||||
self.forecast_lbl_3,
|
||||
@@ -116,7 +132,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.forecast_lbl_5,
|
||||
self.forecast_lbl_6,
|
||||
self.forecast_lbl_7,
|
||||
self.forecast_lbl_8)
|
||||
self.forecast_lbl_8
|
||||
)
|
||||
|
||||
for lab in self.forecast_labels:
|
||||
lab.set_default_stylesheet()
|
||||
@@ -140,20 +157,20 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
)
|
||||
|
||||
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.lower_freq_filter_unit.currentTextChanged,
|
||||
self.upper_freq_filter_unit.currentTextChanged,
|
||||
self.activate_low_freq_filter_btn.toggled],
|
||||
fun_to_connect = self.set_min_value_upper_limit,
|
||||
fun_args = [self.lower_freq_filter_unit,
|
||||
fun_to_connect=self.set_min_value_upper_limit,
|
||||
fun_args=[self.lower_freq_filter_unit,
|
||||
self.lower_freq_spinbox,
|
||||
self.upper_freq_filter_unit,
|
||||
self.upper_freq_spinbox]
|
||||
)
|
||||
|
||||
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.lower_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.lower_freq_confidence.valueChanged,
|
||||
self.upper_freq_confidence.valueChanged],
|
||||
fun_to_connect = self.set_band_filter_label,
|
||||
fun_args = [self.activate_low_freq_filter_btn,
|
||||
fun_to_connect=self.set_band_filter_label,
|
||||
fun_args=[self.activate_low_freq_filter_btn,
|
||||
self.lower_freq_spinbox,
|
||||
self.lower_freq_filter_unit,
|
||||
self.lower_freq_confidence,
|
||||
@@ -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_slave_filters(
|
||||
[
|
||||
simple_ones=[
|
||||
*self.frequency_filters_btns,
|
||||
self.include_undef_freqs,
|
||||
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_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_filter_unit,
|
||||
self.upper_freq_confidence,
|
||||
],
|
||||
self.upper_freq_confidence
|
||||
]
|
||||
)
|
||||
self.apply_remove_freq_filter_btn.clicked.connect(self.display_signals)
|
||||
self.reset_frequency_filters_btn.clicked.connect(partial(self.reset_fb_filters, Ftype.FREQ))
|
||||
self.reset_frequency_filters_btn.clicked.connect(
|
||||
partial(self.reset_fb_filters, Ftype.FREQ)
|
||||
)
|
||||
|
||||
# Manage bandwidth filters.
|
||||
|
||||
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.lower_band_filter_unit.currentTextChanged,
|
||||
self.upper_band_filter_unit.currentTextChanged,
|
||||
self.activate_low_band_filter_btn.toggled],
|
||||
fun_to_connect = self.set_min_value_upper_limit,
|
||||
fun_args = [self.lower_band_filter_unit,
|
||||
fun_args=[self.lower_band_filter_unit,
|
||||
self.lower_band_spinbox,
|
||||
self.upper_band_filter_unit,
|
||||
self.upper_band_spinbox]
|
||||
)
|
||||
|
||||
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.lower_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.lower_band_confidence.valueChanged,
|
||||
self.upper_band_confidence.valueChanged],
|
||||
fun_to_connect = self.set_band_filter_label,
|
||||
fun_args = [self.activate_low_band_filter_btn,
|
||||
fun_to_connect=self.set_band_filter_label,
|
||||
fun_args=[self.activate_low_band_filter_btn,
|
||||
self.lower_band_spinbox,
|
||||
self.lower_band_filter_unit,
|
||||
self.lower_band_confidence,
|
||||
@@ -265,33 +284,37 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
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(
|
||||
[
|
||||
simple_ones=[
|
||||
self.include_undef_bands,
|
||||
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_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_filter_unit,
|
||||
self.upper_band_confidence,
|
||||
],
|
||||
self.upper_band_confidence
|
||||
]
|
||||
)
|
||||
self.apply_remove_band_filter_btn.clicked.connect(self.display_signals)
|
||||
self.reset_band_filters_btn.clicked.connect(partial(self.reset_fb_filters, Ftype.BAND))
|
||||
self.reset_band_filters_btn.clicked.connect(
|
||||
partial(self.reset_fb_filters, Ftype.BAND)
|
||||
)
|
||||
|
||||
# Manage category filters
|
||||
|
||||
# Order matters!
|
||||
self.cat_filter_btns = [self.military_btn,
|
||||
self.cat_filter_btns = [
|
||||
self.military_btn,
|
||||
self.radar_btn,
|
||||
self.active_btn,
|
||||
self.inactive_btn,
|
||||
@@ -307,12 +330,17 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.navigation_btn,
|
||||
self.interfering_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_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_all])
|
||||
self.cat_all
|
||||
]
|
||||
)
|
||||
self.apply_remove_cat_filter_btn.clicked.connect(self.display_signals)
|
||||
self.reset_cat_filters_btn.clicked.connect(self.reset_cat_filters)
|
||||
|
||||
@@ -322,7 +350,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
|
||||
UrlColors = namedtuple("UrlColors", ["inactive", "active", "clicked"])
|
||||
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_active,
|
||||
self.cat_inactive,
|
||||
@@ -338,15 +367,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.cat_navi,
|
||||
self.cat_interf,
|
||||
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.mode_lab,
|
||||
self.modul_lab,
|
||||
self.loc_lab,
|
||||
self.acf_lab,
|
||||
self.description_text,]
|
||||
self.description_text
|
||||
]
|
||||
|
||||
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.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_slave_filters([self.mode_tree_widget,
|
||||
self.include_unknown_modes_btn])
|
||||
self.apply_remove_mode_filter_btn.set_slave_filters(
|
||||
simple_ones=[
|
||||
self.mode_tree_widget,
|
||||
self.include_unknown_modes_btn
|
||||
]
|
||||
)
|
||||
self.apply_remove_mode_filter_btn.clicked.connect(self.display_signals)
|
||||
|
||||
# Set modulation filter screen.
|
||||
@@ -365,8 +401,12 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.modulation_list.addItems(Constants.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_slave_filters([self.search_bar_modulation,
|
||||
self.modulation_list])
|
||||
self.apply_remove_modulation_filter_btn.set_slave_filters(
|
||||
simple_ones=[
|
||||
self.search_bar_modulation,
|
||||
self.modulation_list
|
||||
]
|
||||
)
|
||||
self.apply_remove_modulation_filter_btn.clicked.connect(self.display_signals)
|
||||
self.reset_modulation_filters_btn.clicked.connect(self.reset_modulation_filters)
|
||||
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.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_slave_filters([self.search_bar_location,
|
||||
self.locations_list])
|
||||
self.apply_remove_location_filter_btn.set_slave_filters(
|
||||
simple_ones=[
|
||||
self.search_bar_location,
|
||||
self.locations_list
|
||||
]
|
||||
)
|
||||
self.apply_remove_location_filter_btn.clicked.connect(self.display_signals)
|
||||
self.reset_location_filters_btn.clicked.connect(self.reset_location_filters)
|
||||
self.locations_list.itemClicked.connect(self.remove_if_unselected_location)
|
||||
|
||||
# Set ACF filter screen.
|
||||
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.reset_acf_filters_btn.clicked.connect(self.reset_acf_filters)
|
||||
self.acf_info_btn.clicked.connect(lambda : webbrowser.open(Constants.ACF_DOCS))
|
||||
|
||||
connect_events_to_func(
|
||||
events_to_connect = [self.acf_spinbox.valueChanged, self.acf_confidence.valueChanged],
|
||||
fun_to_connect = self.set_acf_interval_label,
|
||||
fun_args = None
|
||||
events_to_connect=[self.acf_spinbox.valueChanged,
|
||||
self.acf_confidence.valueChanged],
|
||||
fun_to_connect=self.set_acf_interval_label,
|
||||
fun_args=None
|
||||
)
|
||||
|
||||
# GFD
|
||||
@@ -405,14 +456,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
# Left list widget and search bar.
|
||||
self.search_bar.textChanged.connect(self.display_signals)
|
||||
self.result_list.currentItemChanged.connect(self.display_specs)
|
||||
self.result_list.itemDoubleClicked.connect(lambda: self.main_tab.setCurrentWidget(self.signal_properties_tab))
|
||||
self.audio_widget = AudioPlayer(self.play,
|
||||
self.result_list.itemDoubleClicked.connect(
|
||||
lambda: self.main_tab.setCurrentWidget(self.signal_properties_tab)
|
||||
)
|
||||
self.audio_widget = AudioPlayer(
|
||||
self.play,
|
||||
self.pause,
|
||||
self.stop,
|
||||
self.volume,
|
||||
self.audio_progress,
|
||||
self.active_color,
|
||||
self.inactive_color)
|
||||
self.inactive_color
|
||||
)
|
||||
|
||||
BandLabel = namedtuple("BandLabel", ["left", "center", "right"])
|
||||
self.band_labels = [
|
||||
@@ -430,7 +485,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
]
|
||||
|
||||
# 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.set_idle()
|
||||
self.space_weather_data = SpaceWeatherData()
|
||||
@@ -591,16 +648,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
label.pixmap = pixmap
|
||||
label.make_transparent()
|
||||
label.apply_pixmap()
|
||||
else:
|
||||
pop_up(self, title = Messages.BAD_DOWNLOAD,
|
||||
text = Messages.BAD_DOWNLOAD_MSG).show()
|
||||
elif not self.closing:
|
||||
pop_up(self, title=Messages.BAD_DOWNLOAD,
|
||||
text=Messages.BAD_DOWNLOAD_MSG).show()
|
||||
self.space_weather_data.remove_data()
|
||||
|
||||
@pyqtSlot()
|
||||
def go_to_gfd(self, by):
|
||||
query = "/?q="
|
||||
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)
|
||||
elif by is GfdType.LOC:
|
||||
query += self.gfd_line_edit.text()
|
||||
@@ -654,8 +713,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
item.child(i).setSelected(True)
|
||||
|
||||
def set_initial_size(self):
|
||||
"""Function to handle high resolution screens. The function sets bigger sizes
|
||||
for all the relevant fixed-size widgets."""
|
||||
"""Function to handle high resolution screens. The function sets bigger
|
||||
sizes for all the relevant fixed-size widgets."""
|
||||
d = QDesktopWidget().availableGeometry()
|
||||
w = d.width()
|
||||
h = d.height()
|
||||
@@ -719,17 +778,17 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
try:
|
||||
is_checksum_ok = checksum_ok(db, ChecksumWhat.DB)
|
||||
except Exception:
|
||||
pop_up(self, title = Messages.NO_CONNECTION,
|
||||
text = Messages.NO_CONNECTION_MSG).show()
|
||||
pop_up(self, title=Messages.NO_CONNECTION,
|
||||
text=Messages.NO_CONNECTION_MSG).show()
|
||||
else:
|
||||
if not is_checksum_ok:
|
||||
self.download_db()
|
||||
else:
|
||||
answer = pop_up(self, title = Messages.DB_UP_TO_DATE,
|
||||
text = Messages.DB_UP_TO_DATE_MSG,
|
||||
informative_text = Messages.DOWNLOAD_ANYWAY_QUESTION,
|
||||
is_question = True,
|
||||
default_btn = QMessageBox.No).exec()
|
||||
answer = pop_up(self, title=Messages.DB_UP_TO_DATE,
|
||||
text=Messages.DB_UP_TO_DATE_MSG,
|
||||
informative_text=Messages.DOWNLOAD_ANYWAY_QUESTION,
|
||||
is_question=True,
|
||||
default_btn=QMessageBox.No).exec()
|
||||
if answer == QMessageBox.Yes:
|
||||
self.download_db()
|
||||
|
||||
@@ -742,27 +801,27 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
with open(db_path, "rb") as file_db:
|
||||
db = file_db.read()
|
||||
except Exception:
|
||||
answer = pop_up(self, title = Messages.NO_DB,
|
||||
text = Messages.NO_DB_AVAIL,
|
||||
informative_text = Messages.DOWNLOAD_NOW_QUESTION,
|
||||
is_question = True).exec()
|
||||
answer = pop_up(self, title=Messages.NO_DB,
|
||||
text=Messages.NO_DB_AVAIL,
|
||||
informative_text=Messages.DOWNLOAD_NOW_QUESTION,
|
||||
is_question=True).exec()
|
||||
if answer == QMessageBox.Yes:
|
||||
self.download_db()
|
||||
else:
|
||||
try:
|
||||
is_checksum_ok = checksum_ok(db, ChecksumWhat.DB)
|
||||
except Exception:
|
||||
pop_up(self, title = Messages.NO_CONNECTION,
|
||||
text = Messages.NO_CONNECTION_MSG).show()
|
||||
pop_up(self, title=Messages.NO_CONNECTION,
|
||||
text=Messages.NO_CONNECTION_MSG).show()
|
||||
else:
|
||||
if is_checksum_ok:
|
||||
pop_up(self, title = Messages.DB_UP_TO_DATE,
|
||||
text = Messages.DB_UP_TO_DATE_MSG).show()
|
||||
pop_up(self, title=Messages.DB_UP_TO_DATE,
|
||||
text=Messages.DB_UP_TO_DATE_MSG).show()
|
||||
else:
|
||||
answer = pop_up(self, title = Messages.DB_NEW_VER,
|
||||
text = Messages.DB_NEW_VER_MSG,
|
||||
informative_text = Messages.DOWNLOAD_NOW_QUESTION,
|
||||
is_question = True).exec()
|
||||
answer = pop_up(self, title=Messages.DB_NEW_VER,
|
||||
text=Messages.DB_NEW_VER_MSG,
|
||||
informative_text=Messages.DOWNLOAD_NOW_QUESTION,
|
||||
is_question=True).exec()
|
||||
if answer == QMessageBox.Yes:
|
||||
self.download_db()
|
||||
|
||||
@@ -776,23 +835,23 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
names = Database.NAMES
|
||||
try:
|
||||
self.db = read_csv(os.path.join(Constants.DATA_FOLDER, Database.NAME),
|
||||
sep = Database.DELIMITER,
|
||||
header = None,
|
||||
index_col = 0,
|
||||
dtype = {name : str for name in Database.STRINGS},
|
||||
names = names,)
|
||||
sep=Database.DELIMITER,
|
||||
header=None,
|
||||
index_col=0,
|
||||
dtype={name: str for name in Database.STRINGS},
|
||||
names=names)
|
||||
except FileNotFoundError:
|
||||
self.search_bar.setDisabled(True)
|
||||
answer = pop_up(self, title = Messages.NO_DB,
|
||||
text = Messages.NO_DB_AVAIL,
|
||||
informative_text = Messages.DOWNLOAD_NOW_QUESTION,
|
||||
is_question = True).exec()
|
||||
answer = pop_up(self, title=Messages.NO_DB,
|
||||
text=Messages.NO_DB_AVAIL,
|
||||
informative_text=Messages.DOWNLOAD_NOW_QUESTION,
|
||||
is_question=True).exec()
|
||||
if answer == QMessageBox.Yes:
|
||||
self.download_db()
|
||||
else:
|
||||
self.signal_names = self.db.index
|
||||
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.update_status_tip(self.total_signals)
|
||||
self.result_list.clear()
|
||||
@@ -824,11 +883,13 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
upper_combo_box.disconnect()
|
||||
upper_combo_box.setCurrentText(new_unit)
|
||||
upper_combo_box.currentTextChanged.connect(
|
||||
partial(self.set_min_value_upper_limit,
|
||||
partial(
|
||||
self.set_min_value_upper_limit,
|
||||
lower_combo_box,
|
||||
lower_spin_box,
|
||||
upper_combo_box,
|
||||
upper_spin_box)
|
||||
upper_spin_box
|
||||
)
|
||||
)
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -853,7 +914,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
min_value = lower_spinbox.value()
|
||||
if lower_confidence.value() != 0:
|
||||
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:
|
||||
to_display += 'DC'
|
||||
to_display += Constants.RANGE_SEPARATOR
|
||||
@@ -863,7 +925,8 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
color = self.active_color
|
||||
if upper_confidence.value() != 0:
|
||||
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:
|
||||
to_display += 'INF'
|
||||
if activate_low and activate_high:
|
||||
@@ -883,8 +946,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
def set_acf_interval_label(self):
|
||||
tolerance = self.acf_spinbox.value() * self.acf_confidence.value() / 100
|
||||
if tolerance > 0:
|
||||
to_display = f"Selected range:\n\n{round(self.acf_spinbox.value() - tolerance, Constants.MAX_DIGITS)}" +\
|
||||
Constants.RANGE_SEPARATOR + f"{round(self.acf_spinbox.value() + tolerance, Constants.MAX_DIGITS)} ms"
|
||||
val = round(self.acf_spinbox.value() - tolerance, Constants.MAX_DIGITS)
|
||||
to_display = f"Selected range:\n\n{val}" + Constants.RANGE_SEPARATOR \
|
||||
+ f"{round(self.acf_spinbox.value() + tolerance, Constants.MAX_DIGITS)} ms"
|
||||
else:
|
||||
to_display = f"Selected value:\n\n{self.acf_spinbox.value()} ms"
|
||||
self.acf_range_lbl.setText(to_display)
|
||||
@@ -922,12 +986,15 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.statusbar.setStyleSheet(f'color: {self.active_color}')
|
||||
else:
|
||||
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()
|
||||
def reset_fb_filters(self, ftype):
|
||||
if ftype != Ftype.FREQ and ftype != Ftype.BAND:
|
||||
raise ValueError("Wrong ftype in function 'reset_fb_filters'")
|
||||
|
||||
apply_remove_btn = getattr(self, 'apply_remove_' + ftype + '_filter_btn')
|
||||
include_undef_btn = getattr(self, 'include_undef_' + ftype + 's')
|
||||
activate_low = getattr(self, 'activate_low_' + ftype + '_filter_btn')
|
||||
@@ -938,6 +1005,7 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
upper_spinbox = getattr(self, 'upper_' + ftype + '_spinbox')
|
||||
lower_confidence = getattr(self, 'lower_' + ftype + '_confidence')
|
||||
upper_confidence = getattr(self, 'lower_' + ftype + '_confidence')
|
||||
|
||||
default_val = 1 if ftype == Ftype.FREQ else 5000
|
||||
if ftype == Ftype.FREQ:
|
||||
for f in self.frequency_filters_btns:
|
||||
@@ -1013,8 +1081,10 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
else:
|
||||
return False
|
||||
|
||||
signal_freqs = (int(self.db.at[signal_name, Signal.INF_FREQ]),
|
||||
int(self.db.at[signal_name, Signal.SUP_FREQ]))
|
||||
signal_freqs = (
|
||||
int(self.db.at[signal_name, Signal.INF_FREQ]),
|
||||
int(self.db.at[signal_name, Signal.SUP_FREQ])
|
||||
)
|
||||
|
||||
band_filter_ok = False
|
||||
any_checked = False
|
||||
@@ -1050,8 +1120,10 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
else:
|
||||
return False
|
||||
|
||||
signal_bands = (int(self.db.at[signal_name, Signal.INF_BAND]),
|
||||
int(self.db.at[signal_name, Signal.SUP_BAND]))
|
||||
signal_bands = (
|
||||
int(self.db.at[signal_name, Signal.INF_BAND]),
|
||||
int(self.db.at[signal_name, Signal.SUP_BAND])
|
||||
)
|
||||
|
||||
lower_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]
|
||||
self.url_button.setEnabled(True)
|
||||
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:
|
||||
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]
|
||||
undef_freq = is_undef_freq(current_signal)
|
||||
undef_band = is_undef_band(current_signal)
|
||||
if not undef_freq:
|
||||
self.freq_lab.setText(format_numbers(current_signal.at[Signal.INF_FREQ],
|
||||
current_signal.at[Signal.SUP_FREQ])
|
||||
self.freq_lab.setText(
|
||||
format_numbers(
|
||||
current_signal.at[Signal.INF_FREQ],
|
||||
current_signal.at[Signal.SUP_FREQ]
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.freq_lab.setText("Undefined")
|
||||
if not undef_band:
|
||||
self.band_lab.setText(format_numbers(current_signal.at[Signal.INF_BAND],
|
||||
current_signal.at[Signal.SUP_BAND])
|
||||
self.band_lab.setText(
|
||||
format_numbers(
|
||||
current_signal.at[Signal.INF_BAND],
|
||||
current_signal.at[Signal.SUP_BAND]
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.band_lab.setText("Undefined")
|
||||
@@ -1183,7 +1265,9 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.audio_widget.set_audio_player(self.current_signal_name)
|
||||
else:
|
||||
self.url_button.setEnabled(False)
|
||||
self.url_button.setStyleSheet(f"color: {self.url_button.colors.inactive};")
|
||||
self.url_button.setStyleSheet(
|
||||
f"color: {self.url_button.colors.inactive};"
|
||||
)
|
||||
self.current_signal_name = ''
|
||||
self.name_lab.setText("No Signal")
|
||||
self.name_lab.setAlignment(Qt.AlignHCenter)
|
||||
@@ -1195,15 +1279,23 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
self.audio_widget.set_audio_player()
|
||||
|
||||
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()
|
||||
if item:
|
||||
spectrogram_name = item.text()
|
||||
path_spectr = os.path.join(Constants.DATA_FOLDER,
|
||||
path_spectr = os.path.join(
|
||||
Constants.DATA_FOLDER,
|
||||
Constants.SPECTRA_FOLDER,
|
||||
spectrogram_name + Constants.SPECTRA_EXT)
|
||||
spectrogram_name + Constants.SPECTRA_EXT
|
||||
)
|
||||
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:
|
||||
path_spectr = default_pic
|
||||
self.spectrogram.setPixmap(QPixmap(path_spectr))
|
||||
@@ -1247,13 +1339,18 @@ class Artemis(QMainWindow, Ui_MainWindow):
|
||||
@pyqtSlot()
|
||||
def go_to_web_page_signal(self):
|
||||
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])
|
||||
self.db.at[self.current_signal_name, Signal.WIKI_CLICKED] = True
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.closing = True
|
||||
if self.download_window.isVisible():
|
||||
self.download_window.close()
|
||||
if self.space_weather_data.is_updating:
|
||||
self.space_weather_data.shutdown_thread()
|
||||
super().closeEvent(event)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import os
|
||||
import sys
|
||||
from pydub import AudioSegment
|
||||
from pygame import mixer
|
||||
from PyQt5.QtCore import QTimer, pyqtSlot, QObject
|
||||
@@ -9,11 +8,9 @@ import qtawesome as qta
|
||||
|
||||
|
||||
class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
||||
"""
|
||||
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. Everything else
|
||||
is managed internally.
|
||||
"""
|
||||
"""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.
|
||||
Everything else is managed internally."""
|
||||
|
||||
__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):
|
||||
self.__play.setIcon(qta.icon('fa5.play-circle',
|
||||
color = active_color,
|
||||
color_disabled = inactive_color))
|
||||
color=active_color,
|
||||
color_disabled=inactive_color))
|
||||
self.__pause.setIcon(qta.icon('fa5.pause-circle',
|
||||
color = active_color,
|
||||
color_disabled = inactive_color))
|
||||
color=active_color,
|
||||
color_disabled=inactive_color))
|
||||
self.__stop.setIcon(qta.icon('fa5.stop-circle',
|
||||
color = active_color,
|
||||
color_disabled = inactive_color))
|
||||
color=active_color,
|
||||
color_disabled=inactive_color))
|
||||
|
||||
@pyqtSlot()
|
||||
def __set_volume(self):
|
||||
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):
|
||||
if mixer.get_init():
|
||||
@@ -82,7 +81,11 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
||||
def set_audio_player(self, fname = ""):
|
||||
self.__first_call = True
|
||||
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):
|
||||
self.__play.setEnabled(True)
|
||||
self.__audio_file = full_name
|
||||
@@ -92,8 +95,10 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject
|
||||
if not self.__paused:
|
||||
if self.__first_call:
|
||||
self.__first_call = False
|
||||
mixer.init(frequency = AudioSegment.from_ogg(self.__audio_file).frame_rate,
|
||||
buffer = 2048)
|
||||
mixer.init(frequency=AudioSegment.from_ogg(
|
||||
self.__audio_file
|
||||
).frame_rate,
|
||||
buffer=2048)
|
||||
mixer.music.load(self.__audio_file)
|
||||
self.__set_volume()
|
||||
self.__set_max_progress_bar()
|
||||
|
||||
@@ -2,11 +2,12 @@ from PyQt5.QtWidgets import QProgressBar
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from constants import Constants
|
||||
|
||||
|
||||
class ClickableProgressBar(QProgressBar):
|
||||
|
||||
clicked = pyqtSignal()
|
||||
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent=None):
|
||||
self.__text = ''
|
||||
super().__init__(parent)
|
||||
|
||||
|
||||
31
constants.py
31
constants.py
@@ -1,18 +1,22 @@
|
||||
from collections import namedtuple
|
||||
from enum import Enum, auto
|
||||
|
||||
|
||||
class Ftype(object):
|
||||
FREQ = "freq"
|
||||
BAND = "band"
|
||||
|
||||
|
||||
class GfdType(Enum):
|
||||
FREQ = auto()
|
||||
LOC = auto()
|
||||
|
||||
|
||||
class ChecksumWhat(Enum):
|
||||
FOLDER = auto()
|
||||
DB = auto()
|
||||
|
||||
|
||||
class Messages(object):
|
||||
DB_UP_TO_DATE = "Already up to date"
|
||||
DB_UP_TO_DATE_MSG = "No newer version to download."
|
||||
@@ -27,6 +31,7 @@ class Messages(object):
|
||||
BAD_DOWNLOAD = "Something went wrong"
|
||||
BAD_DOWNLOAD_MSG = "Something went wrong with the downaload.\nCheck your internet connection and try again."
|
||||
|
||||
|
||||
class Signal(object):
|
||||
NAME = "name"
|
||||
INF_FREQ = "inf_freq"
|
||||
@@ -42,6 +47,7 @@ class Signal(object):
|
||||
ACF = "acf"
|
||||
WIKI_CLICKED = "url_clicked"
|
||||
|
||||
|
||||
class Database(object):
|
||||
LINK_LOC = "https://aresvalley.com/Storage/Artemis/Database/data.zip"
|
||||
LINK_REF = "https://aresvalley.com/Storage/Artemis/Database/data.zip.log"
|
||||
@@ -66,25 +72,26 @@ class Database(object):
|
||||
Signal.SUP_BAND,
|
||||
Signal.CATEGORY_CODE,)
|
||||
|
||||
|
||||
class Constants(object):
|
||||
CLICK_TO_UPDATE_STR = "Click to update"
|
||||
UPDATING_STR = "Updating..."
|
||||
ACF_DOCS = "https://aresvalley.com/documentation/"
|
||||
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_AK_IND = "https://services.swpc.noaa.gov/text/wwv.txt"
|
||||
FORECAST_PROT_EL = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt"
|
||||
FORECAST_AK_INDEX = "https://services.swpc.noaa.gov/text/wwv.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_IMG_0 = "http://www.mmmonvhf.de/eme/eme.png"
|
||||
FORECAST_IMG_1 = "http://www.mmmonvhf.de/ms/ms.png"
|
||||
FORECAST_IMG_2 = "http://www.mmmonvhf.de/es/es.png"
|
||||
FORECAST_IMG_3 = "http://www.mmmonvhf.de/solar/solar.png"
|
||||
FORECAST_IMG_4 = "http://amunters.home.xs4all.nl/eskipstatusNA.gif"
|
||||
FORECAST_IMG_5 = "http://amunters.home.xs4all.nl/aurorastatus.gif"
|
||||
FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskipstatus.gif"
|
||||
FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip50status.gif"
|
||||
FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskip70status.gif"
|
||||
FORECAST_IMGS = ["http://www.mmmonvhf.de/eme/eme.png",
|
||||
"http://www.mmmonvhf.de/ms/ms.png",
|
||||
"http://www.mmmonvhf.de/es/es.png",
|
||||
"http://www.mmmonvhf.de/solar/solar.png",
|
||||
"http://amunters.home.xs4all.nl/eskipstatusNA.gif",
|
||||
"http://amunters.home.xs4all.nl/aurorastatus.gif",
|
||||
"http://amunters.home.xs4all.nl/eskipstatus.gif",
|
||||
"http://amunters.home.xs4all.nl/eskip50status.gif",
|
||||
"http://amunters.home.xs4all.nl/eskip70status.gif"]
|
||||
SEARCH_LABEL_IMG = "search_icon.png"
|
||||
VOLUME_LABEL_IMG = "volume.png"
|
||||
DATA_FOLDER = "Data"
|
||||
|
||||
@@ -2,7 +2,7 @@ from PyQt5.QtWidgets import QPushButton
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
|
||||
class DoubleTextButton(QPushButton):
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.clicked.connect(self.__manage_click)
|
||||
|
||||
@@ -10,11 +10,11 @@ class DoubleTextButton(QPushButton):
|
||||
self.__text_a = text_a
|
||||
self.__text_b = text_b
|
||||
|
||||
def set_slave_filters(self, simple_ones = None,
|
||||
radio_1 = None,
|
||||
ruled_by_radio_1 = None,
|
||||
radio_2 = None,
|
||||
ruled_by_radio_2 = None):
|
||||
def set_slave_filters(self, simple_ones=None,
|
||||
radio_1=None,
|
||||
ruled_by_radio_1=None,
|
||||
radio_2=None,
|
||||
ruled_by_radio_2=None):
|
||||
self.__simple_ones = simple_ones
|
||||
self.__ruled_by_radio_1 = ruled_by_radio_1
|
||||
self.__radio_1 = radio_1
|
||||
|
||||
@@ -7,6 +7,7 @@ from constants import Messages
|
||||
|
||||
Ui_Download_window, _ = uic.loadUiType(resource_path("download_db_window.ui"))
|
||||
|
||||
|
||||
class DownloadWindow(QWidget, Ui_Download_window):
|
||||
|
||||
complete = pyqtSignal()
|
||||
@@ -22,13 +23,13 @@ class DownloadWindow(QWidget, Ui_Download_window):
|
||||
# Qt.WindowStaysOnTopHint
|
||||
)
|
||||
|
||||
self.no_internet_msg = pop_up(self, title = Messages.NO_CONNECTION,
|
||||
text = Messages.NO_CONNECTION_MSG,
|
||||
connection = self.close)
|
||||
self.no_internet_msg = pop_up(self, title=Messages.NO_CONNECTION,
|
||||
text=Messages.NO_CONNECTION_MSG,
|
||||
connection=self.close)
|
||||
|
||||
self.bad_db_download_msg = pop_up(self, title = Messages.BAD_DOWNLOAD,
|
||||
text = Messages.BAD_DOWNLOAD_MSG,
|
||||
connection = self.close)
|
||||
self.bad_db_download_msg = pop_up(self, title=Messages.BAD_DOWNLOAD,
|
||||
text=Messages.BAD_DOWNLOAD_MSG,
|
||||
connection=self.close)
|
||||
|
||||
self.download_thread = DownloadThread()
|
||||
self.download_thread.finished.connect(self.wait_close)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
|
||||
class FixedAspectRatioLabel(QLabel):
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
@@ -20,7 +21,9 @@ class FixedAspectRatioLabel(QLabel):
|
||||
if self.pixmap:
|
||||
self.setPixmap(
|
||||
self.pixmap.scaled(
|
||||
self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
|
||||
self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation
|
||||
)
|
||||
)
|
||||
|
||||
def rescale(self, size):
|
||||
self.resize(size)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
from PyQt5.QtCore import QSize
|
||||
|
||||
|
||||
class FixedAspectRatioWidget(QWidget):
|
||||
space = 10
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.labels = []
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
aiohttp==3.5.4
|
||||
altgraph==0.16.1
|
||||
asn1crypto==0.24.0
|
||||
async-timeout==3.0.1
|
||||
attrs==19.1.0
|
||||
certifi==2019.3.9
|
||||
cffi==1.11.5
|
||||
chardet==3.0.4
|
||||
cryptography==2.3.1
|
||||
Cython==0.29.6
|
||||
future==0.16.0
|
||||
idna==2.7
|
||||
intel-openmp==2019.0
|
||||
macholib==1.11
|
||||
multidict==4.5.2
|
||||
numpy==1.15.2
|
||||
pandas==0.23.4
|
||||
pefile==2018.8.8
|
||||
@@ -28,3 +33,4 @@ six==1.11.0
|
||||
urllib3==1.24
|
||||
win-inet-pton==1.0.1
|
||||
wincertstore==0.2
|
||||
yarl==1.3.0
|
||||
|
||||
@@ -2,6 +2,7 @@ from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
||||
from threads import UpadteSpaceWeatherThread, ThreadStatus
|
||||
|
||||
|
||||
class SpaceWeatherData(QObject):
|
||||
update_complete = pyqtSignal(bool)
|
||||
|
||||
@@ -12,7 +13,7 @@ class SpaceWeatherData(QObject):
|
||||
self.ak_index = ''
|
||||
self.sgas = ''
|
||||
self.geo_storm = ''
|
||||
self.images = [QPixmap(),
|
||||
self.images = [
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
@@ -20,7 +21,9 @@ class SpaceWeatherData(QObject):
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
QPixmap()]
|
||||
QPixmap(),
|
||||
QPixmap()
|
||||
]
|
||||
self.__update_thread = UpadteSpaceWeatherThread(self)
|
||||
self.__update_thread.finished.connect(self.__parse_and_emit_signal)
|
||||
|
||||
@@ -33,7 +36,7 @@ class SpaceWeatherData(QObject):
|
||||
self.__update_thread.start()
|
||||
|
||||
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.prot_el = double_split(self.prot_el)
|
||||
self.ak_index = double_split(self.ak_index)
|
||||
@@ -46,7 +49,7 @@ class SpaceWeatherData(QObject):
|
||||
self.ak_index = ''
|
||||
self.sgas = ''
|
||||
self.geo_storm = ''
|
||||
self.images = [QPixmap(),
|
||||
self.images = [
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
@@ -54,13 +57,18 @@ class SpaceWeatherData(QObject):
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
QPixmap(),
|
||||
QPixmap()]
|
||||
QPixmap(),
|
||||
QPixmap()
|
||||
]
|
||||
|
||||
@pyqtSlot()
|
||||
def __parse_and_emit_signal(self):
|
||||
if self.__update_thread.status is not ThreadStatus.OK:
|
||||
status_ok = False
|
||||
else:
|
||||
if self.__update_thread.status is ThreadStatus.OK:
|
||||
status_ok = True
|
||||
self.__parse_data()
|
||||
self.update_complete.emit(status_ok)
|
||||
|
||||
def shutdown_thread(self):
|
||||
self.__update_thread.terminate()
|
||||
self.__update_thread.wait()
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
|
||||
|
||||
class SwitchableLabel(QLabel):
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.switch_on_colors = ()
|
||||
self.switch_off_colors = ()
|
||||
|
||||
221
themes.py
221
themes.py
@@ -9,6 +9,7 @@ from constants import Constants
|
||||
from switchable_label import SwitchableLabelsIterable
|
||||
from utilities import pop_up
|
||||
|
||||
|
||||
class ThemeConstants(object):
|
||||
FOLDER = "themes"
|
||||
EXTENSION = ".qss"
|
||||
@@ -34,27 +35,41 @@ class Theme(object):
|
||||
self.__theme_path = ""
|
||||
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.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_g_now_labels,
|
||||
self.__parent.switchable_g_today_labels,
|
||||
self.__parent.k_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("switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS)
|
||||
self.__forecast_labels.set(
|
||||
"switch_on_colors",
|
||||
ThemeConstants.DEFAULT_ON_COLORS
|
||||
)
|
||||
self.__forecast_labels.set(
|
||||
"switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS
|
||||
)
|
||||
|
||||
self.__theme_names = {}
|
||||
self.__detect_themes()
|
||||
|
||||
def __refresh_range_labels(self):
|
||||
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_filter_unit,
|
||||
self.__parent.lower_band_confidence,
|
||||
@@ -62,9 +77,11 @@ class Theme(object):
|
||||
self.__parent.upper_band_spinbox,
|
||||
self.__parent.upper_band_filter_unit,
|
||||
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_filter_unit,
|
||||
self.__parent.lower_freq_confidence,
|
||||
@@ -72,16 +89,23 @@ class Theme(object):
|
||||
self.__parent.upper_freq_spinbox,
|
||||
self.__parent.upper_freq_filter_unit,
|
||||
self.__parent.upper_freq_confidence,
|
||||
self.__parent.freq_range_lbl)
|
||||
self.__parent.freq_range_lbl
|
||||
)
|
||||
|
||||
@pyqtSlot()
|
||||
def __apply(self, theme_path):
|
||||
self.__theme_path = theme_path
|
||||
if self.__theme_path != self.__current_theme:
|
||||
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.__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()
|
||||
|
||||
def __pretty_name(self, bad_name):
|
||||
@@ -93,7 +117,7 @@ class Theme(object):
|
||||
|
||||
def __detect_themes(self):
|
||||
themes = []
|
||||
ag = QActionGroup(self.__parent, exclusive = True)
|
||||
ag = QActionGroup(self.__parent, exclusive=True)
|
||||
for theme_folder in os.listdir(ThemeConstants.FOLDER):
|
||||
relative_folder = os.path.join(ThemeConstants.FOLDER, theme_folder)
|
||||
if os.path.isdir(os.path.abspath(relative_folder)):
|
||||
@@ -101,27 +125,46 @@ class Theme(object):
|
||||
themes.append(relative_folder)
|
||||
for theme_path in themes:
|
||||
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.__theme_names[theme_name.lstrip('&')] = new_theme
|
||||
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):
|
||||
theme_name = os.path.basename(self.__theme_path).split('-')[1] + ThemeConstants.EXTENSION
|
||||
try:
|
||||
with open(os.path.join(
|
||||
self.__theme_path,
|
||||
os.path.basename(self.__theme_path).split('-')[1] + ThemeConstants.EXTENSION), "r") as stylesheet:
|
||||
with open(
|
||||
os.path.join(self.__theme_path, theme_name), "r"
|
||||
) as stylesheet:
|
||||
style = stylesheet.read()
|
||||
self.__parent.setStyleSheet(style)
|
||||
self.__parent.download_window.setStyleSheet(style)
|
||||
except FileNotFoundError:
|
||||
pop_up(self.__parent, title = ThemeConstants.THEME_NOT_FOUND,
|
||||
text = ThemeConstants.MISSING_THEME).show()
|
||||
pop_up(self.__parent, title=ThemeConstants.THEME_NOT_FOUND,
|
||||
text=ThemeConstants.MISSING_THEME).show()
|
||||
else:
|
||||
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.ICONS_FOLDER)
|
||||
ThemeConstants.ICONS_FOLDER
|
||||
)
|
||||
|
||||
if os.path.exists(os.path.join(icons_path, Constants.NOT_SELECTED)) and \
|
||||
os.path.exists(os.path.join(icons_path, Constants.NOT_AVAILABLE)):
|
||||
@@ -129,33 +172,65 @@ class Theme(object):
|
||||
else:
|
||||
self.__parent.default_images_folder = default_icons_path
|
||||
|
||||
path_to_search_label = os.path.join(icons_path, Constants.SEARCH_LABEL_IMG)
|
||||
default_search_label = os.path.join(default_icons_path, Constants.SEARCH_LABEL_IMG)
|
||||
path_to_search_label = os.path.join(
|
||||
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):
|
||||
self.__parent.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))
|
||||
self.__parent.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:
|
||||
self.__parent.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.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.modulation_search_label.setScaledContents(True)
|
||||
self.__parent.location_search_label.setScaledContents(True)
|
||||
|
||||
path_to_volume_label = os.path.join(icons_path, Constants.VOLUME_LABEL_IMG)
|
||||
default_volume_label = os.path.join(default_icons_path, Constants.VOLUME_LABEL_IMG)
|
||||
path_to_volume_label = os.path.join(
|
||||
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):
|
||||
self.__parent.volume_label.setPixmap(QPixmap(path_to_volume_label))
|
||||
self.__parent.volume_label.setPixmap(
|
||||
QPixmap(path_to_volume_label)
|
||||
)
|
||||
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)
|
||||
|
||||
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
|
||||
inactive_color_ok = False
|
||||
switch_on_color_ok = False
|
||||
@@ -163,57 +238,78 @@ class Theme(object):
|
||||
text_color_ok = False
|
||||
|
||||
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:
|
||||
for line in colors_file:
|
||||
if ThemeConstants.COLOR_SEPARATOR in line:
|
||||
quality, color = line.split(ThemeConstants.COLOR_SEPARATOR)
|
||||
color = color.rstrip()
|
||||
color_len = 1
|
||||
if ',' in color:
|
||||
color = [c.rstrip().lstrip() for c in color.split(',')]
|
||||
else:
|
||||
color = [color]
|
||||
if len(color) > 2:
|
||||
break
|
||||
if is_valid_html_color(color):
|
||||
color = [c.strip() for c in color.split(',')]
|
||||
color_len = len(color)
|
||||
if self.__is_valid_html_color(color):
|
||||
if color_len == 1:
|
||||
if quality.lower() == Constants.ACTIVE:
|
||||
self.__parent.active_color = color[0]
|
||||
self.__parent.active_color = color
|
||||
active_color_ok = True
|
||||
if quality.lower() == Constants.INACTIVE:
|
||||
self.__parent.inactive_color = color[0]
|
||||
self.__parent.inactive_color = color
|
||||
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:
|
||||
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):
|
||||
self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR
|
||||
self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR
|
||||
|
||||
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("switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS)
|
||||
self.__forecast_labels.set(
|
||||
"switch_on_colors",
|
||||
ThemeConstants.DEFAULT_ON_COLORS
|
||||
)
|
||||
self.__forecast_labels.set(
|
||||
"switch_off_colors",
|
||||
ThemeConstants.DEFAULT_OFF_COLORS
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
try:
|
||||
with open(os.path.join(ThemeConstants.FOLDER,
|
||||
ThemeConstants.CURRENT), "w") as current_theme:
|
||||
with open(os.path.join(
|
||||
ThemeConstants.FOLDER,
|
||||
ThemeConstants.CURRENT
|
||||
), "w") as current_theme:
|
||||
current_theme.write(self.__theme_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
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):
|
||||
with open(current_theme_file, "r") as current_theme_path:
|
||||
theme_path = current_theme_path.read()
|
||||
@@ -221,5 +317,12 @@ class Theme(object):
|
||||
self.__theme_names[theme_name].setChecked(True)
|
||||
self.__apply(theme_path)
|
||||
else:
|
||||
self.__theme_names[self.__pretty_name(ThemeConstants.DEFAULT)].setChecked(True)
|
||||
self.__apply(os.path.join(ThemeConstants.FOLDER, ThemeConstants.DEFAULT))
|
||||
self.__theme_names[
|
||||
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 io import BytesIO
|
||||
import os.path
|
||||
from shutil import rmtree
|
||||
import urllib3
|
||||
from zipfile import ZipFile
|
||||
import aiohttp
|
||||
import urllib3
|
||||
from PyQt5.QtCore import QThread
|
||||
from constants import Constants, Database, ChecksumWhat
|
||||
from utilities import checksum_ok
|
||||
|
||||
|
||||
class ThreadStatus(Enum):
|
||||
OK = auto()
|
||||
NO_CONNECTION_ERR = auto()
|
||||
@@ -15,38 +18,42 @@ class ThreadStatus(Enum):
|
||||
BAD_DOWNLOAD_ERR = auto()
|
||||
UNDEFINED = auto()
|
||||
|
||||
class DownloadThread(QThread):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.__status = ThreadStatus.UNDEFINED
|
||||
self.reason = 0
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
return self.__status
|
||||
class _BaseDownloadThread(QThread):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.status = ThreadStatus.UNDEFINED
|
||||
|
||||
def __del__(self):
|
||||
self.terminate()
|
||||
self.wait()
|
||||
super().__del__()
|
||||
|
||||
|
||||
class DownloadThread(_BaseDownloadThread):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.reason = 0
|
||||
|
||||
def run(self):
|
||||
self.status = ThreadStatus.UNDEFINED
|
||||
try:
|
||||
db = urllib3.PoolManager().request('GET', Database.LINK_LOC)
|
||||
except urllib3.exceptions.MaxRetryError: # No internet connection.
|
||||
self.__status = ThreadStatus.NO_CONNECTION_ERR
|
||||
self.status = ThreadStatus.NO_CONNECTION_ERR
|
||||
return
|
||||
if db.status != 200:
|
||||
self.reason = db.reason
|
||||
self.__status = ThreadStatus.BAD_DOWNLOAD_ERR
|
||||
self.status = ThreadStatus.BAD_DOWNLOAD_ERR
|
||||
return
|
||||
try:
|
||||
is_checksum_ok = checksum_ok(db.data, ChecksumWhat.FOLDER)
|
||||
except Exception:
|
||||
self.__status = ThreadStatus.NO_CONNECTION_ERR
|
||||
self.status = ThreadStatus.NO_CONNECTION_ERR
|
||||
return
|
||||
else:
|
||||
if not is_checksum_ok:
|
||||
self.__status = ThreadStatus.BAD_DOWNLOAD_ERR
|
||||
self.status = ThreadStatus.BAD_DOWNLOAD_ERR
|
||||
return
|
||||
if os.path.exists(Constants.DATA_FOLDER):
|
||||
rmtree(Constants.DATA_FOLDER)
|
||||
@@ -54,43 +61,55 @@ class DownloadThread(QThread):
|
||||
with ZipFile(BytesIO(db.data)) as zipped:
|
||||
zipped.extractall()
|
||||
except Exception:
|
||||
self.__status = ThreadStatus.UNKNOWN_ERR
|
||||
self.status = ThreadStatus.UNKNOWN_ERR
|
||||
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):
|
||||
super().__init__()
|
||||
self.__status = ThreadStatus.UNDEFINED
|
||||
self.__space_weather_data = space_weather_data
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
return self.__status
|
||||
async def __download_resource(self, session, link):
|
||||
resp = await session.get(link)
|
||||
return await resp.read()
|
||||
|
||||
def __del__(self):
|
||||
self.terminate()
|
||||
self.wait()
|
||||
async def __download_property(self, session, property_name):
|
||||
link = getattr(Constants, "FORECAST_" + property_name.upper())
|
||||
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):
|
||||
get_request_data = lambda link: urllib3.PoolManager().request('GET', link).data
|
||||
try:
|
||||
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
|
||||
self.status = ThreadStatus.UNDEFINED
|
||||
asyncio.run(self.__download_resources())
|
||||
|
||||
18
utilities.py
18
utilities.py
@@ -21,10 +21,10 @@ def uncheck_and_emit(button):
|
||||
button.clicked.emit()
|
||||
|
||||
def pop_up(cls, title, text,
|
||||
informative_text = None,
|
||||
connection = None,
|
||||
is_question = False,
|
||||
default_btn = QMessageBox.Yes):
|
||||
informative_text=None,
|
||||
connection=None,
|
||||
is_question=False,
|
||||
default_btn=QMessageBox.Yes):
|
||||
msg = QMessageBox(cls)
|
||||
msg.setWindowTitle(title)
|
||||
msg.setText(text)
|
||||
@@ -48,21 +48,23 @@ def checksum_ok(data, what):
|
||||
else:
|
||||
raise ValueError("Wrong entry name.")
|
||||
try:
|
||||
reference = read_csv(Database.LINK_REF,
|
||||
delimiter = Database.DELIMITER).iat[-1, n]
|
||||
reference = read_csv(
|
||||
Database.LINK_REF,
|
||||
delimiter=Database.DELIMITER
|
||||
).iat[-1, n]
|
||||
except Exception:
|
||||
raise
|
||||
return code.hexdigest() == reference
|
||||
|
||||
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:
|
||||
event.connect(partial(fun_to_connect, *fun_args))
|
||||
else:
|
||||
for event in events_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()]
|
||||
return band_filter + sign * (confidence.value() * band_filter) // 100
|
||||
|
||||
|
||||
Reference in New Issue
Block a user