diff --git a/HashDatabase.py b/HashDatabase.py index 88d285f..3bd87a0 100644 --- a/HashDatabase.py +++ b/HashDatabase.py @@ -19,7 +19,7 @@ def load_hashsets(path, status_callback=None): if os.path.isfile(filename): hashset = os.path.basename(filename).split('.')[0] if status_callback: - status_callback('Reading Hashset "{}"...'.format(hashset)) + status_callback.emit('Reading Hashset "{}"...'.format(hashset)) hashes = read_hashset_file(filename) hashsets[hashset] = set(hashes) return hashsets diff --git a/main.ui b/main.ui index cd142cb..c4e704d 100644 --- a/main.ui +++ b/main.ui @@ -105,7 +105,7 @@ 0 0 532 - 21 + 22 diff --git a/pyMuleAnalyzerQT.py b/pyMuleAnalyzerQT.py index eafcd8d..ee55081 100644 --- a/pyMuleAnalyzerQT.py +++ b/pyMuleAnalyzerQT.py @@ -3,11 +3,16 @@ """ import sys +import os +import traceback +import time +import random + import PyQt5 -from PyQt5.QtCore import Qt, QDateTime, QObject, pyqtSignal +from PyQt5.QtCore import Qt, QDateTime, QObject, pyqtSignal, pyqtSlot, QRunnable, QThreadPool from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QAbstractItemView, \ QTableWidgetItem, QSplashScreen, QProgressBar -from PyQt5.QtGui import QStandardItemModel, QPixmap +from PyQt5.QtGui import QStandardItemModel, QPixmap, QMovie, QPainter from MuleAnalyzerUI import Ui_MainWindow from ED2K import load_knownfiles @@ -30,6 +35,63 @@ sys._excepthook = sys.excepthook sys.excepthook = exceptionHandler.handler +class MovieSplashScreen(QSplashScreen): + + def __init__(self, movie, parent=None): + movie.jumpToFrame(0) + pixmap = QPixmap(movie.frameRect().size()) + QSplashScreen.__init__(self, pixmap, Qt.WindowStaysOnTopHint) + self.movie = movie + self.movie.frameChanged.connect(self.repaint) + + def showEvent(self, event): + self.movie.start() + + def hideEvent(self, event): + self.movie.stop() + + def paintEvent(self, event): + painter = QPainter(self) + pixmap = self.movie.currentPixmap() + self.setMask(pixmap.mask()) + painter.drawPixmap(0, 0, pixmap) + + def sizeHint(self): + return self.movie.scaledSize() + + +class WorkerSignals(QObject): + finished = pyqtSignal() + error = pyqtSignal(tuple) + result = pyqtSignal(object) + progress = pyqtSignal(str) + + +class Worker(QRunnable): + + def __init__(self, fn, *args, **kwargs): + QRunnable.__init__(self) + self.fn = fn + self.args = args + self.kwargs = kwargs + self.signals = WorkerSignals() + kwargs['progress_callback'] = self.signals.progress + + @pyqtSlot() + def run(self): + # Retrieve args/kwargs here; and fire processing using them + try: + result = self.fn(*self.args, **self.kwargs) + except: + traceback.print_exc() + exctype, value = sys.exc_info()[:2] + self.signals.error.emit((exctype, value, traceback.format_exc())) + else: + self.signals.result.emit(result) + finally: + self.signals.finished.emit() + + class MainWindow(QMainWindow, Ui_MainWindow): # Todo: Replace TreeHeaders @@ -51,8 +113,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): ('Parts Hash', 'PARTHASHES', list, '', Qt.AlignLeft), ) - def __init__(self): - self.is_loading = False + def __init__(self, *args, **kwargs): super(MainWindow, self).__init__() self.setupUi(self) @@ -70,14 +131,32 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.actionFile_open.triggered.connect(self.slot_load_met_file) self.actionExit.triggered.connect(self.close) - # Init functionality and other features - self.hashsets = load_hashsets('Hashsets', self.cb_print_msg) - self.is_loading = True + self.threadpool = QThreadPool() + self.hashsets = None + self.splash_screen = kwargs['splash_screen'] + worker = Worker(self.load_hashsets) + worker.signals.result.connect(self.cb_got_hashset) + worker.signals.progress.connect(self.cb_progress) + self.threadpool.start(worker) + + def cb_progress(self, msg): + self.splash_screen.showMessage('

%s

' % msg, Qt.AlignTop | Qt.AlignCenter, Qt.black) + + def load_hashsets(self, progress_callback, folder='Hashsets'): + self.hashsets = load_hashsets(folder, progress_callback) + return self.hashsets def cb_print_msg(self, message): - PyQt5.QtWidgets.QApplication.processEvents() print('>>>', message) + def cb_got_hashset(self, hashes): + num_hashsets = len(hashes.keys()) + num_hashes = 0 + for key in hashes: + num_hashes += len(hashes[key]) + self.statusBar.showMessage('Loaded {} hashsets with {:,} hashes.'.format(num_hashsets, + num_hashes)) + def createED2KModel(self, parent): model = QStandardItemModel(0, len(self.Headers), parent) for i, fields in enumerate(self.Headers): @@ -117,10 +196,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): for met_entry in load_knownfiles(filename): self.addED2K(self.treeModel, met_entry) + @pyqtSlot() def slot_load_met_file(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog - files, _ = QFileDialog.getOpenFileNames(self, 'Open .met files...', '', 'MET Files (*.met);;All Files (*)', + files, _ = QFileDialog.getOpenFileNames(self, 'Open .met files...', '', + 'MET Files (*.met);;All Files (*)', options=options) for filename in files: self.loadMetFile(filename) @@ -140,15 +221,20 @@ class MainWindow(QMainWindow, Ui_MainWindow): def main(argv): app = QApplication(argv) - splash_pix = QPixmap('splash-screen.jpg') - splash_screen = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint) - splash_screen.setMask(splash_pix.mask()) - + resources = './resources/loaders/' + movies = [] + for filename in os.listdir(resources): + filepath = os.path.join(resources, filename) + if os.path.isfile(filepath): + movies.append(filepath) + movie = QMovie(random.choice(movies)) + splash_screen = MovieSplashScreen(movie) + splash_screen.setEnabled(False) splash_screen.show() - splash_screen.showMessage('

EY // eMuleAnalyzer

', Qt.AlignTop | Qt.AlignCenter, Qt.black) - app.processEvents() - window = MainWindow() + window = MainWindow(splash_screen=splash_screen) + while not window.hashsets: + app.processEvents() window.show() splash_screen.finish(window) diff --git a/resources/loaders/loader-01.gif b/resources/loaders/loader-01.gif new file mode 100644 index 0000000..1f69660 Binary files /dev/null and b/resources/loaders/loader-01.gif differ diff --git a/resources/loaders/loader-02.gif b/resources/loaders/loader-02.gif new file mode 100644 index 0000000..8eb2df6 Binary files /dev/null and b/resources/loaders/loader-02.gif differ diff --git a/resources/loaders/loader-03.gif b/resources/loaders/loader-03.gif new file mode 100644 index 0000000..87e4b12 Binary files /dev/null and b/resources/loaders/loader-03.gif differ diff --git a/resources/loaders/loader-04.gif b/resources/loaders/loader-04.gif new file mode 100644 index 0000000..78e442c Binary files /dev/null and b/resources/loaders/loader-04.gif differ diff --git a/resources/loaders/loader-05.gif b/resources/loaders/loader-05.gif new file mode 100644 index 0000000..2e4e8bf Binary files /dev/null and b/resources/loaders/loader-05.gif differ diff --git a/resources/loaders/loader-06.gif b/resources/loaders/loader-06.gif new file mode 100644 index 0000000..b716151 Binary files /dev/null and b/resources/loaders/loader-06.gif differ diff --git a/resources/loaders/loader-07.gif b/resources/loaders/loader-07.gif new file mode 100644 index 0000000..a4ca664 Binary files /dev/null and b/resources/loaders/loader-07.gif differ