Add download db window with connection checks

This commit is contained in:
alessandro90
2018-11-03 17:44:09 +01:00
parent c50c98b2d3
commit e28d3b6286
6 changed files with 294 additions and 41 deletions

View File

@@ -15,8 +15,10 @@ class AudioPlayer(QObject):
__time_step = 500 # Milliseconds. __time_step = 500 # Milliseconds.
def __init__(self, play, pause, stop, volume, audio_progress): def __init__(self, play, pause, stop, volume, audio_progress, data_folder, audio_folder):
super().__init__() super().__init__()
self.__data_folder = data_folder
self.__audio_folder = audio_folder
self.__paused = False self.__paused = False
self.__first_call = True self.__first_call = True
self.__play = play self.__play = play
@@ -77,7 +79,7 @@ class AudioPlayer(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('Data', 'Audio_ogg', fname + '.ogg') full_name = os.path.join(self.__data_folder, self.__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

112
download_db_window.ui Normal file
View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
<string>Download database</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget {
background-color: #464646
}
QLabel {
color: #ffffff;
}
QProgressBar {
border: 2px #7a7a7a;
border-radius: 5px;
background-color: #7a7a7a;
}
QProgressBar::chunk {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #1d5eff, stop:0.5 #4177ff, stop:1 #1d5eff);
border-radius: 5px;
}
QMessageBox {
color: #ffffff;
}
QPushButton {
color: #ffffff;
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Downloading database
Please wait</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancel_btn">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
background-color: rgb(52,52,52);
color: #FFFFFF;
border: 1px solid gray;
border-radius: 8px;
}
</string>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

43
download_thread.py Normal file
View File

@@ -0,0 +1,43 @@
from io import BytesIO
from os import mkdir
import os.path
from shutil import rmtree
import urllib
from zipfile import ZipFile
from PyQt5.QtCore import QThread, pyqtSignal
class DownloadThread(QThread):
no_connection_error = pyqtSignal()
bad_db_download_error = pyqtSignal()
def __init__(self, db_location, path):
super().__init__()
self.__db_location = db_location
self.__path = path
self.regular_execution = True
self.reason = 0
def __del__(self):
self.terminate()
self.wait()
def run(self):
if os.path.exists(self.__path):
rmtree(self.__path)
try:
db = urllib.request.urlopen(self.__db_location)
# raise urllib.error.URLError('Test')
except urllib.error.URLError: # No internet connection.
self.regular_execution = False
self.no_connection_error.emit()
return
if db.status != 200:
self.regular_execution = False
self.reason = db.reason
self.bad_db_download_error.emit()
return
try:
with ZipFile(BytesIO(db.read())) as zipped:
zipped.extractall()
except:
pass

63
download_window.py Normal file
View File

@@ -0,0 +1,63 @@
from PyQt5 import uic
from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtWidgets import QWidget, QMessageBox
from download_thread import DownloadThread
Ui_Download_window, _ = uic.loadUiType("download_db_window.ui")
class DownloadWindow(QWidget, Ui_Download_window):
def __init__(self, db_location, data_folder):
super().__init__()
self.setupUi(self)
self.setWindowFlags(
#Qt.Window |
Qt.CustomizeWindowHint |
Qt.WindowTitleHint |
Qt.WindowCloseButtonHint #|
# Qt.WindowStaysOnTopHint
)
self.everything_ok = True
self.no_internet_msg = QMessageBox(self)
self.no_internet_msg.setWindowTitle("No internet connection")
self.no_internet_msg.setText("Unable to establish an internet connection")
# self.no_internet_msg.buttonClicked.connect(self.close)
self.no_internet_msg.finished.connect(self.close)
self.bad_db_download_msg = QMessageBox(self)
self.bad_db_download_msg.setWindowTitle("Something wrong")
self.bad_db_download_msg.finished.connect(self.close)
self.download_thread = DownloadThread(db_location, data_folder)
self.download_thread.finished.connect(self.wait_close)
self.download_thread.no_connection_error.connect(self.show_no_connection_warning)
self.download_thread.bad_db_download_error.connect(self.show_bad_download_warning)
self.cancel_btn.clicked.connect(self.terminate_process)
@pyqtSlot()
def show_no_connection_warning(self):
self.bad_db_download_msg.setText(f"Unable to correctly download the database.\nReason: {self.download_thread.reason}")
self.no_internet_msg.show()
self.everything_ok = False
@pyqtSlot()
def show_bad_download_warning(self):
self.bad_db_download_msg.show()
self.everything_ok = False
@pyqtSlot()
def terminate_process(self):
if self.download_thread.isRunning():
self.download_thread.terminate()
self.download_thread.wait()
self.close()
@pyqtSlot()
def wait_close(self):
if self.download_thread.regular_execution:
self.close()
def reject(self):
if self.download_thread.isRunning():
self.download_thread.terminate()
self.download_thread.wait()
super().reject()

97
main.py
View File

@@ -13,17 +13,26 @@ from PyQt5.QtWidgets import (QMainWindow,
QListWidgetItem,) QListWidgetItem,)
from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QPixmap
from PyQt5 import uic from PyQt5 import uic
from PyQt5.QtCore import QFileInfo, QSize, Qt, pyqtSlot from PyQt5.QtCore import (QFileInfo,
QSize,
Qt,
pyqtSlot,)
from audio_player import AudioPlayer from audio_player import AudioPlayer
from double_text_button import DoubleTextButton from double_text_button import DoubleTextButton
from download_window import DownloadWindow
qt_creator_file = "main_window.ui" qt_creator_file = "main_window.ui"
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file) Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
class MyApp(QMainWindow, Ui_MainWindow): class MyApp(QMainWindow, Ui_MainWindow):
db_location = 'https://aresvalley.com/Storage/Artemis/Database/data.zip'
data_folder = 'Data'
spectra_folder = 'Spectra'
audio_folder = 'Audio'
icons_folder = 'icons_imgs'
Band = namedtuple("Band", ["lower", "upper"]) Band = namedtuple("Band", ["lower", "upper"])
ELF = Band(0, 30) # Formally it is (3, 30) Hz. ELF = Band(0, 30) # Formally it is (3, 30) Hz.
SLF = Band(30, 300) SLF = Band(30, 300)
@@ -45,8 +54,10 @@ class MyApp(QMainWindow, Ui_MainWindow):
super().__init__() super().__init__()
self.setupUi(self) self.setupUi(self)
self.set_initial_size() self.set_initial_size()
self.download_window = DownloadWindow(self.db_location, self.data_folder)
self.show() self.show()
self.actionExit.triggered.connect(qApp.quit) self.actionExit.triggered.connect(qApp.quit)
self.action_update_database.triggered.connect(self.download_db)
self.db_version = None self.db_version = None
self.db = None self.db = None
self.current_signal_name = '' self.current_signal_name = ''
@@ -286,7 +297,9 @@ class MyApp(QMainWindow, Ui_MainWindow):
self.pause, self.pause,
self.stop, self.stop,
self.volume, self.volume,
self.audio_progress) self.audio_progress,
self.data_folder,
self.audio_folder)
BandLabel = namedtuple("BandLabel", ["left", "center", "right"]) BandLabel = namedtuple("BandLabel", ["left", "center", "right"])
self.band_labels = [ self.band_labels = [
@@ -324,6 +337,14 @@ class MyApp(QMainWindow, Ui_MainWindow):
self.upper_freq_filter_unit.setFixedWidth(120) self.upper_freq_filter_unit.setFixedWidth(120)
self.lower_freq_confidence.setFixedWidth(120) self.lower_freq_confidence.setFixedWidth(120)
self.upper_freq_confidence.setFixedWidth(120) self.upper_freq_confidence.setFixedWidth(120)
self.lower_band_spinbox.setFixedWidth(200)
self.upper_band_spinbox.setFixedWidth(200)
self.lower_band_filter_unit.setFixedWidth(120)
self.upper_band_filter_unit.setFixedWidth(120)
self.lower_band_confidence.setFixedWidth(120)
self.upper_band_confidence.setFixedWidth(120)
self.audio_progress.setFixedHeight(20) self.audio_progress.setFixedHeight(20)
self.volume.setStyleSheet(""" self.volume.setStyleSheet("""
QSlider::groove:horizontal { QSlider::groove:horizontal {
@@ -341,6 +362,19 @@ class MyApp(QMainWindow, Ui_MainWindow):
} }
""") """)
@pyqtSlot()
def download_db(self):
self.download_window.download_thread.finished.connect(self.show_downloaded_signals)
self.download_window.download_thread.start()
self.download_window.show()
@pyqtSlot()
def show_downloaded_signals(self):
if self.download_window.everything_ok:
self.search_bar.setEnabled(True)
self.load_db()
self.display_signals()
def load_db(self): def load_db(self):
names = ["name", names = ["name",
"inf_freq", "inf_freq",
@@ -355,7 +389,7 @@ class MyApp(QMainWindow, Ui_MainWindow):
"category_code", "category_code",
"acf",] "acf",]
try: try:
self.db = read_csv(os.path.join('Data', 'db.csv'), self.db = read_csv(os.path.join(self.data_folder, 'db.csv'),
sep = '*', sep = '*',
header = None, header = None,
index_col = 0, index_col = 0,
@@ -371,27 +405,14 @@ class MyApp(QMainWindow, Ui_MainWindow):
box = QMessageBox(self) box = QMessageBox(self)
box.setWindowTitle("No database") box.setWindowTitle("No database")
box.setText("No database available.\n" box.setText("No database available.\n"
"Go to Updates->Download database.") "Go to Updates->Update database.")
box.show() box.show()
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("N/A", inplace = True) self.db.fillna("N/A", inplace = True)
self.db["url_clicked"] = False self.db["url_clicked"] = False
try: self.update_status_tip(self.total_signals)
with open(os.path.join('Data', 'verdb.ini'), 'r') as dbver:
self.db_version = int(dbver.read())
except (FileNotFoundError, ValueError):
box = QMessageBox(self)
box.setWindowTitle("No database version")
box.setText("Unable to detect database version.\n"
"Possible data curruption.\n"
"Go to Updates->Force Download.")
box.show()
self.statusbar.setStyleSheet(f'color: {self.active_color}')
self.statusbar.showMessage("Database version: undefined.")
else:
self.update_status_tip(self.total_signals)
@staticmethod @staticmethod
def connect_to(objects_to_connect, fun_to_connect, fun_args): def connect_to(objects_to_connect, fun_to_connect, fun_args):
@@ -556,7 +577,7 @@ class MyApp(QMainWindow, Ui_MainWindow):
def frequency_filters_ok(self, signal_name): def frequency_filters_ok(self, signal_name):
if not self.apply_remove_freq_filter_btn.isChecked(): if not self.apply_remove_freq_filter_btn.isChecked():
return True return True
undef_freq, _ = self.find_if_undefined(self.db.loc[signal_name]) undef_freq = self.is_undef_freq(self.db.loc[signal_name])
if undef_freq: if undef_freq:
if self.include_undef_freqs.isChecked(): if self.include_undef_freqs.isChecked():
return True return True
@@ -593,7 +614,7 @@ class MyApp(QMainWindow, Ui_MainWindow):
def band_filters_ok(self, signal_name): def band_filters_ok(self, signal_name):
if not self.apply_remove_band_filter_btn.isChecked(): if not self.apply_remove_band_filter_btn.isChecked():
return True return True
_, undef_band = self.find_if_undefined(self.db.loc[signal_name]) undef_band = self.is_undef_band(self.db.loc[signal_name])
if undef_band: if undef_band:
if self.include_undef_bands.isChecked(): if self.include_undef_bands.isChecked():
return True return True
@@ -652,7 +673,8 @@ class MyApp(QMainWindow, Ui_MainWindow):
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["category_code"] category_code = current_signal.at["category_code"]
undef_freq, undef_band = self.find_if_undefined(current_signal) undef_freq = self.is_undef_freq(current_signal)
undef_band = self.is_undef_band(current_signal)
if not undef_freq: if not undef_freq:
self.freq_lab.setText(self.format_numbers( self.freq_lab.setText(self.format_numbers(
current_signal.at["inf_freq"], current_signal.at["inf_freq"],
@@ -694,20 +716,16 @@ class MyApp(QMainWindow, Ui_MainWindow):
self.audio_widget.set_audio_player() self.audio_widget.set_audio_player()
@staticmethod @staticmethod
def find_if_undefined(current_signal): def is_undef_freq(current_signal):
lower_freq = current_signal.at["inf_freq"] lower_freq = current_signal.at["inf_freq"]
lower_band = current_signal.at["inf_band"]
upper_freq = current_signal.at["sup_freq"] upper_freq = current_signal.at["sup_freq"]
return lower_freq == 'N/A' or upper_freq == 'N/A'
@staticmethod
def is_undef_band(current_signal):
lower_band = current_signal.at["inf_band"]
upper_band = current_signal.at["sup_band"] upper_band = current_signal.at["sup_band"]
if lower_freq == '0' and upper_freq == "100000000000": return lower_band == 'N/A' or upper_band == 'N/A'
undefined_freq = True
else:
undefined_freq = False
if lower_band == '0' and upper_band == '100000000':
undefined_band = True
else:
undefined_band = False
return undefined_freq, undefined_band
@classmethod @classmethod
def format_numbers(cls, lower, upper): def format_numbers(cls, lower, upper):
@@ -740,13 +758,13 @@ class MyApp(QMainWindow, Ui_MainWindow):
return 10**9 return 10**9
def display_spectrogram(self): def display_spectrogram(self):
default_pic = os.path.join("icons_imgs", "nosignalselected.png") default_pic = os.path.join(self.icons_folder, "nosignalselected.png")
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("Data", "Spectra", spectrogram_name + ".jpg") path_spectr = os.path.join(self.data_folder, self.spectra_folder, spectrogram_name + ".png")
if not QFileInfo(path_spectr).exists(): if not QFileInfo(path_spectr).exists():
path_spectr = os.path.join("icons_imgs", "spectrumnotavailable.png") path_spectr = os.path.join(self.icons_folder, "spectrumnotavailable.png")
else: else:
path_spectr = default_pic path_spectr = default_pic
self.spectrogram.setPixmap(QPixmap(path_spectr)) self.spectrogram.setPixmap(QPixmap(path_spectr))
@@ -758,7 +776,7 @@ class MyApp(QMainWindow, Ui_MainWindow):
label.setStyleSheet(f"color: {color};") label.setStyleSheet(f"color: {color};")
def set_band_range(self, current_signal = None): def set_band_range(self, current_signal = None):
if current_signal is not None and not self.find_if_undefined(current_signal)[0]: if current_signal is not None and not self.is_undef_freq(current_signal):
lower_freq = int(current_signal.at["inf_freq"]) lower_freq = int(current_signal.at["inf_freq"])
upper_freq = int(current_signal.at["sup_freq"]) upper_freq = int(current_signal.at["sup_freq"])
zipped = list(zip(self.bands, self.band_labels)) zipped = list(zip(self.bands, self.band_labels))
@@ -791,6 +809,11 @@ class MyApp(QMainWindow, Ui_MainWindow):
webbrowser.open(self.db.at[self.current_signal_name, "url"]) webbrowser.open(self.db.at[self.current_signal_name, "url"])
self.db.at[self.current_signal_name, "url_clicked"] = True self.db.at[self.current_signal_name, "url_clicked"] = True
def closeEvent(self, event):
if self.download_window.isVisible():
self.download_window.close()
super().closeEvent(event)
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -323,7 +323,7 @@ QPushButton:!enabled {
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<property name="movable"> <property name="movable">
<bool>true</bool> <bool>true</bool>
@@ -4032,11 +4032,15 @@ QMenuBar::item:selected {
QMenu::item:selected { QMenu::item:selected {
background-color: #999999; background-color: #999999;
color: #1d5eff color: #1d5eff
}
QMenu {
color: #ffffff;
}</string> }</string>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255);</string> <string notr="true"/>
</property> </property>
<property name="title"> <property name="title">
<string>File</string> <string>File</string>
@@ -4047,6 +4051,7 @@ QMenu::item:selected {
<property name="title"> <property name="title">
<string>Updates</string> <string>Updates</string>
</property> </property>
<addaction name="action_update_database"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuUpdates"/> <addaction name="menuUpdates"/>
@@ -4061,6 +4066,11 @@ QMenu::item:selected {
<string>Exit</string> <string>Exit</string>
</property> </property>
</action> </action>
<action name="action_update_database">
<property name="text">
<string>Update database</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>