diff --git a/.gitignore b/.gitignore index 5aed056..917bc1e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ pyinstaller_cmd.txt icons_imgs TestData themes/.current_theme +*.bat +*.sh diff --git a/constants.py b/constants.py index 0289848..94ecf23 100644 --- a/constants.py +++ b/constants.py @@ -9,22 +9,9 @@ class ChecksumWhat(Enum): FOLDER = auto() DB = auto() -class Theme(object): - FOLDER = "themes" - EXTENSION = ".qss" - ICONS_FOLDER = "icons" - DEFAULT = "1-system" - CURRENT = ".current_theme" - COLORS = "colors.txt" - COLOR_SEPARATOR = "=" - DEFAULT_ACTIVE_COLOR = "#39eaff" - DEFAULT_INACTIVE_COLOR = "#9f9f9f" - class Messages(object): NO_DB_AVAIL = "No database available.\nGo to Updates->Update database." NO_DB = "No database" - THEME_NOT_FOUND = "Theme not found" - MISSING_THEME = "Missing theme in " + Theme.FOLDER + " folder." NO_CONNECTION = "No internet connection" NO_CONNECTION_MSG = "Unable to establish an internet connection." BAD_DOWNLOAD = "Something went wrong" @@ -70,6 +57,7 @@ class Database(object): Signal.INF_BAND, Signal.SUP_BAND, Signal.CATEGORY_CODE,) + ACF_DOCS = "https://aresvalley.com/documentation/" SEARCH_LABEL_IMG = "search_icon.png" VOLUME_LABEL_IMG = "volume.png" diff --git a/main.py b/main.py index 5e1f6d2..4551f66 100644 --- a/main.py +++ b/main.py @@ -4,20 +4,20 @@ from glob import glob import webbrowser import os import sys +from time import sleep from pandas import read_csv from PyQt5.QtWidgets import (QMainWindow, QApplication, - QAction, qApp, QDesktopWidget, QListWidgetItem, + QSplashScreen, QTreeView, QTreeWidgetItem,) from PyQt5.QtGui import QPixmap from PyQt5 import uic from PyQt5.QtCore import (QFileInfo, - QSize, Qt, pyqtSlot,) @@ -27,10 +27,10 @@ from double_text_button import DoubleTextButton from download_window import DownloadWindow import constants +from themes import Theme from utilities import (uncheck_and_emit, throwable_message, - is_valid_html_color, connect_to, filters_ok, is_undef_freq, @@ -54,8 +54,7 @@ class MyApp(QMainWindow, Ui_MainWindow): self.current_signal_name = '' self.signal_names = [] self.total_signals = 0 - self.active_color = constants.Theme.DEFAULT_ACTIVE_COLOR - self.inactive_color = constants.Theme.DEFAULT_INACTIVE_COLOR + self.theme = Theme(self) # Manage frequency filters. self.frequency_filters_btns = ( @@ -328,11 +327,6 @@ class MyApp(QMainWindow, Ui_MainWindow): fun_args = None ) - # Find available themes. - self.default_images_folder = os.path.join(constants.Theme.FOLDER, - constants.Theme.DEFAULT, - constants.Theme.ICONS_FOLDER) - # ########################################################################################## self.load_db() @@ -366,8 +360,7 @@ class MyApp(QMainWindow, Ui_MainWindow): BandLabel(self.ehf_left, self.ehf, self.ehf_right), ] - self.find_themes() - self.set_theme() + self.theme.initialize() self.show() @@ -392,119 +385,6 @@ class MyApp(QMainWindow, Ui_MainWindow): self.upper_freq_confidence, self.freq_range_lbl) - @pyqtSlot() - def show_theme(self, theme): - self.change_theme(theme) - self.display_specs(self.result_list.currentItem(), None) - self.refresh_range_labels() - self.audio_widget.refresh_btns_colors(self.active_color, self.inactive_color) - - def find_themes(self): - themes = [] - for theme_folder in os.listdir(constants.Theme.FOLDER): - relative_folder = os.path.join(constants.Theme.FOLDER, theme_folder) - if os.path.isdir(os.path.abspath(relative_folder)): - relative_folder = os.path.join(constants.Theme.FOLDER, theme_folder) - themes.append(relative_folder) - for theme in themes: - theme_name = '&' + ' '.join( - map(lambda s: s.capitalize(), - os.path.basename(theme).split('-')[1].split('_') - ) - ) - new_theme = QAction(theme_name, self) - self.menu_themes.addAction(new_theme) - - new_theme.triggered.connect(partial(self.show_theme, theme)) - - @pyqtSlot() - def change_theme(self, theme_path): - try: - with open(os.path.join( - theme_path, - os.path.basename(theme_path).split('-')[1] + constants.Theme.EXTENSION) - ) as stylesheet: - style = stylesheet.read() - self.setStyleSheet(style) - self.download_window.setStyleSheet(style) - except FileNotFoundError: - throwable_message(self, title = constants.Messages.THEME_NOT_FOUND, - text = constants.Messages.MISSING_THEME).show() - else: - icons_path = os.path.join(theme_path, constants.Theme.ICONS_FOLDER) - default_icons_path = os.path.join(constants.Theme.FOLDER, constants.Theme.DEFAULT, constants.Theme.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)): - self.default_images_folder = icons_path - else: - self.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) - - if os.path.exists(path_to_search_label): - self.search_label.setPixmap(QPixmap(path_to_search_label)) - self.modulation_search_label.setPixmap(QPixmap(path_to_search_label)) - self.location_search_label.setPixmap(QPixmap(path_to_search_label)) - else: - self.search_label.setPixmap(QPixmap(default_search_label)) - self.modulation_search_label.setPixmap(QPixmap(default_search_label)) - self.location_search_label.setPixmap(QPixmap(default_search_label)) - - self.search_label.setScaledContents(True) - self.modulation_search_label.setScaledContents(True) - self.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) - - if os.path.exists(path_to_volume_label): - self.volume_label.setPixmap(QPixmap(path_to_volume_label)) - else: - self.volume_label.setPixmap(QPixmap(default_volume_label)) - - self.volume_label.setScaledContents(True) - - path_to_colors = os.path.join(theme_path, constants.Theme.COLORS) - active_color_ok = False - inactive_color_ok = False - valid_format = False - valid_file = False - if os.path.exists(path_to_colors): - valid_file = True - with open(path_to_colors, "r") as colors_file: - for line in colors_file: - if constants.Theme.COLOR_SEPARATOR in line: - valid_format = True - quality, color = line.split(constants.Theme.COLOR_SEPARATOR) - color = color.rstrip() - if quality.lower() == constants.ACTIVE and is_valid_html_color(color): - self.active_color = color - active_color_ok = True - if quality.lower() == constants.INACTIVE and is_valid_html_color(color): - self.inactive_color = color - inactive_color_ok = True - - if not all([valid_file, valid_format, active_color_ok, inactive_color_ok]): - self.active_color = constants.Theme.DEFAULT_ACTIVE_COLOR - self.inactive_color = constants.Theme.DEFAULT_INACTIVE_COLOR - - try: - with open(os.path.join(constants.Theme.FOLDER, - constants.Theme.CURRENT), "w") as current_theme: - current_theme.write(theme_path) - except: - pass - - def set_theme(self): - current_theme_file = os.path.join(constants.Theme.FOLDER, constants.Theme.CURRENT) - if os.path.exists(current_theme_file): - with open(current_theme_file) as current_theme: - theme = current_theme.read() - if theme != constants.Theme.DEFAULT: - self.show_theme(theme) - @pyqtSlot(QListWidgetItem) def remove_if_unselected_modulation(self, item): if not item.isSelected(): @@ -1079,8 +959,14 @@ class MyApp(QMainWindow, Ui_MainWindow): super().closeEvent(event) - if __name__ == '__main__': my_app = QApplication(sys.argv) + img = QPixmap("splash.jpg") + img = img.scaled(600, 600, aspectRatioMode = Qt.KeepAspectRatio) + splash = QSplashScreen(img) + splash.show() + splash.showMessage("Loading database...") + sleep(2) w = MyApp() + splash.finish(w) sys.exit(my_app.exec_()) \ No newline at end of file diff --git a/splash.jpg b/splash.jpg new file mode 100644 index 0000000..c83acfc Binary files /dev/null and b/splash.jpg differ diff --git a/themes.py b/themes.py new file mode 100644 index 0000000..7973af1 --- /dev/null +++ b/themes.py @@ -0,0 +1,166 @@ +from functools import partial +import os +from PyQt5.QtWidgets import QAction +from PyQt5.QtCore import pyqtSlot +from PyQt5.QtGui import QPixmap +import constants +from utilities import (throwable_message, + is_valid_html_color,) + +class ThemeConstants(object): + FOLDER = "themes" + EXTENSION = ".qss" + ICONS_FOLDER = "icons" + DEFAULT = "1-system" + CURRENT = ".current_theme" + COLORS = "colors.txt" + COLOR_SEPARATOR = "=" + DEFAULT_ACTIVE_COLOR = "#39eaff" + DEFAULT_INACTIVE_COLOR = "#9f9f9f" + THEME_NOT_FOUND = "Theme not found" + MISSING_THEME = "Missing theme in " + FOLDER + " folder." + +class Theme(object): + def __init__(self, parent): + self.__parent = parent + self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR + self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR + self.__theme_path = ThemeConstants.DEFAULT + self.__parent.default_images_folder = os.path.join(ThemeConstants.FOLDER, + ThemeConstants.DEFAULT, + ThemeConstants.ICONS_FOLDER) + 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.lower_band_spinbox, + self.__parent.lower_band_filter_unit, + self.__parent.lower_band_confidence, + self.__parent.activate_up_band_filter_btn, + self.__parent.upper_band_spinbox, + self.__parent.upper_band_filter_unit, + self.__parent.upper_band_confidence, + self.__parent.band_range_lbl) + 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, + self.__parent.activate_up_freq_filter_btn, + self.__parent.upper_freq_spinbox, + self.__parent.upper_freq_filter_unit, + self.__parent.upper_freq_confidence, + self.__parent.freq_range_lbl) + + @pyqtSlot() + def __apply(self, theme_path): + self.__theme_path = theme_path + self.__change() + self.__parent.display_specs(self.__parent.result_list.currentItem(), None) + self.__refresh_range_labels() + self.__parent.audio_widget.refresh_btns_colors(self.__parent.active_color, self.__parent.inactive_color) + + def __detect_themes(self): + themes = [] + 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)): + relative_folder = os.path.join(ThemeConstants.FOLDER, theme_folder) + themes.append(relative_folder) + for theme_path in themes: + theme_name = '&' + ' '.join( + map(lambda s: s.capitalize(), + os.path.basename(theme_path).split('-')[1].split('_') + ) + ) + new_theme = QAction(theme_name, self.__parent) + self.__parent.menu_themes.addAction(new_theme) + new_theme.triggered.connect(partial(self.__apply, theme_path)) + + def __change(self): + try: + with open(os.path.join( + self.__theme_path, + os.path.basename(self.__theme_path).split('-')[1] + ThemeConstants.EXTENSION)) as stylesheet: + style = stylesheet.read() + self.__parent.setStyleSheet(style) + self.__parent.download_window.setStyleSheet(style) + except FileNotFoundError: + throwable_message(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, + ThemeConstants.DEFAULT, + 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)): + self.__parent.default_images_folder = icons_path + 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) + + 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)) + 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.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) + + if os.path.exists(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.setScaledContents(True) + + path_to_colors = os.path.join(self.__theme_path, ThemeConstants.COLORS) + active_color_ok = False + inactive_color_ok = False + valid_format = False + valid_file = False + if os.path.exists(path_to_colors): + valid_file = True + with open(path_to_colors, "r") as colors_file: + for line in colors_file: + if ThemeConstants.COLOR_SEPARATOR in line: + valid_format = True + quality, color = line.split(ThemeConstants.COLOR_SEPARATOR) + color = color.rstrip() + if quality.lower() == constants.ACTIVE and is_valid_html_color(color): + self.__parent.active_color = color + active_color_ok = True + if quality.lower() == constants.INACTIVE and is_valid_html_color(color): + self.__parent.inactive_color = color + inactive_color_ok = True + + if not all([valid_file, valid_format, active_color_ok, inactive_color_ok]): + self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR + self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR + + try: + with open(os.path.join(ThemeConstants.FOLDER, + ThemeConstants.CURRENT), "w") as current_theme: + current_theme.write(self.__theme_path) + except: + pass + + def initialize(self): + current_theme_file = os.path.join(ThemeConstants.FOLDER, ThemeConstants.CURRENT) + if os.path.exists(current_theme_file): + with open(current_theme_file) as current_theme_path: + theme_path = current_theme_path.read() + if theme_path != ThemeConstants.DEFAULT: + self.__apply(theme_path) \ No newline at end of file