diff --git a/src/plugins/logfile/filterwidget.py b/src/plugins/logfile/filterwidget.py index 5eda202..00a1481 100644 --- a/src/plugins/logfile/filterwidget.py +++ b/src/plugins/logfile/filterwidget.py @@ -2,12 +2,13 @@ import os import re import tempfile import threading +import time from typing import Optional, Callable from PySide6.QtCore import QRunnable, QThreadPool, Signal from PySide6.QtGui import QIcon from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QPushButton, QComboBox, \ - QSizePolicy + QSizePolicy, QProgressBar from src.ui.bigtext.bigtext import BigText from src.ui.bigtext.logFileModel import LogFileModel @@ -26,6 +27,7 @@ class FilterTask(QRunnable): regex: re.Pattern, lock: threading.RLock, filter_match_found_listeners: Callable[[int], None], + progress_handler: Callable[[float], None], on_before: Callable[[], None], on_finish: Callable[[], None] ): @@ -33,6 +35,7 @@ class FilterTask(QRunnable): self.source_model = source_model self.filter_model = filter_model self.regex = regex + self.progress_handler = progress_handler self.on_before = on_before self.on_finish = on_finish self.lock = lock @@ -52,6 +55,7 @@ class FilterTask(QRunnable): for listener in self.filter_match_found_listeners: listener(-1, -1) # notify listeners that a new search started + last_progress_report = time.time() try: with open(self.source_model.get_file(), "rb") as source: with open(self.filter_model.get_file(), "w+b") as target: @@ -62,7 +66,6 @@ class FilterTask(QRunnable): line = l.decode("utf8", errors="ignore") if self.regex.findall(line): - # time.sleep(0.5) lines_written = lines_written + 1 source_line_offset = source.tell() - len(l) target_line_offset = target.tell() @@ -72,9 +75,16 @@ class FilterTask(QRunnable): # sometime buffering can hide results for a while # We force a flush periodically. - if line_count % 10000 == 0 and lines_written > 0: - target.flush() - lines_written = 0 + if line_count % 10000 == 0: + if lines_written > 0: + target.flush() + lines_written = 0 + + now = time.time() + if now - last_progress_report > 0.2: + progress = source.tell() / os.stat(self.source_model.get_file()).st_size + self.progress_handler(progress) + last_progress_report = now if self.aborted: # print("aborted ", time.time()) @@ -88,6 +98,7 @@ class FilterWidget(QWidget): filter_model: LogFileModel filter_task: Optional[FilterTask] = None search_is_running = Signal(bool) + signal_update_progress = Signal(float) def __init__(self, source_model: LogFileModel): super(FilterWidget, self).__init__() @@ -106,10 +117,15 @@ class FilterWidget(QWidget): self.query_field.lineEdit().returnPressed.connect(self.filter_changed) self.query_field.setInsertPolicy(QComboBox.NoInsert) + self.progress_bar = QProgressBar() + self.progress_bar.setVisible(False) + self.progress_bar.setMaximumWidth(50) + self.signal_update_progress.connect(self.update_progress) + self.btn_cancel_search = QPushButton(_("Cancel")) self.btn_cancel_search.setVisible(False) self.btn_cancel_search.pressed.connect(self._cancel_search) - self.search_is_running.connect(lambda is_running: self.btn_cancel_search.setVisible(is_running)) + self.search_is_running.connect(self.search_running_status_changed) self.btn_bookmark = QPushButton(QIcon("icons/ionicons/star.svg"), "") self.btn_bookmark.setToolTip(_("save query")) @@ -127,6 +143,7 @@ class FilterWidget(QWidget): filter_bar.layout = QHBoxLayout(filter_bar) filter_bar.layout.setContentsMargins(0, 0, 0, 0) filter_bar.layout.addWidget(self.query_field) + filter_bar.layout.addWidget(self.progress_bar) filter_bar.layout.addWidget(self.btn_cancel_search) filter_bar.layout.addWidget(self.btn_bookmark) filter_bar.layout.addWidget(self.ignore_case) @@ -140,7 +157,7 @@ class FilterWidget(QWidget): self.layout.addWidget(filter_bar) self.layout.addWidget(self.hits_view) - self.filter_match_found_listeners: [Callable[[int], None]] = [] + self.filter_match_found_listeners: [Callable[[int, int], None]] = [] def on_reveal(self): self._reload_save_queries() @@ -183,6 +200,16 @@ class FilterWidget(QWidget): self.filter_model.clear_query_highlight() PluginRegistry.execute("update_ui") + def search_running_status_changed(self, is_running: bool): + self.btn_cancel_search.setVisible(is_running) + self.progress_bar.setVisible(is_running) + + def update_progress(self, progress: float): + self.progress_bar.setValue(progress * 100) + + def progress_handler(self, progress: float): + self.signal_update_progress.emit(progress) + def filter_changed(self): query = self.query_field.currentText() ignore_case = self.ignore_case.isChecked() @@ -206,6 +233,8 @@ class FilterWidget(QWidget): self.filter_model.truncate() return + self.progress_bar.setValue(0) + self.source_model.set_query_highlight(query, ignore_case, is_regex) self.filter_model.set_query_highlight(query, ignore_case, is_regex) @@ -215,6 +244,7 @@ class FilterWidget(QWidget): regex, self._lock, self.filter_match_found_listeners, + self.progress_handler, lambda: self.search_is_running.emit(True), lambda: self.search_is_running.emit(False) )