add cancel button

This commit is contained in:
2021-10-27 19:16:57 +02:00
parent 851805118d
commit e426b816ef

View File

@@ -1,11 +1,12 @@
import os import os
import re import re
import tempfile import tempfile
import threading
import time import time
from typing import Optional from typing import Optional, Callable
from PyQt6.QtCore import QRunnable, QThreadPool from PyQt6.QtCore import QRunnable, QThreadPool
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QCheckBox from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QCheckBox, QPushButton
from bigtext import BigText from bigtext import BigText
from logFileModel import LogFileModel from logFileModel import LogFileModel
@@ -19,36 +20,46 @@ class FilterTask(QRunnable):
self, self,
source_model: LogFileModel, source_model: LogFileModel,
filter_model: LogFileModel, filter_model: LogFileModel,
regex: re.Pattern regex: re.Pattern,
lock: threading.RLock,
on_before: Callable[[], None],
on_finish: Callable[[], None]
): ):
super(FilterTask, self).__init__() super(FilterTask, self).__init__()
self.source_model = source_model self.source_model = source_model
self.filter_model = filter_model self.filter_model = filter_model
self.regex = regex self.regex = regex
self.future = asyncio.Future() self.on_before = on_before
self.on_finish = on_finish
self.lock = lock
def run(self): def run(self):
# print("writing to tmp file", self.filter_model.get_file()) # print("writing to tmp file", self.filter_model.get_file())
start = time.time()
with open(self.source_model.get_file(), "rb") as source:
with open(self.filter_model.get_file(), "w+b") as target:
while l := source.readline():
line = l.decode("utf8", errors="ignore")
if self.regex.findall(line): # the lock ensures that we only start a new search when the previous search already ended
target.write(line.encode("utf8")) with self.lock:
self.on_before()
try:
with open(self.source_model.get_file(), "rb") as source:
with open(self.filter_model.get_file(), "w+b") as target:
while l := source.readline():
line = l.decode("utf8", errors="ignore")
if self.aborted or self.future.cancelled(): if self.regex.findall(line):
print("aborted") target.write(line.encode("utf8"))
break
#print("filtering for %s took %s" % (self.regex, time.time() - start)) if self.aborted:
self.future.done() #print("aborted ", time.time())
break
finally:
self.on_finish()
class FilterWidget(QWidget): class FilterWidget(QWidget):
future = None future = None
filter_model: LogFileModel filter_model: LogFileModel
filter_task: Optional[FilterTask] = None filter_task: Optional[FilterTask] = None
_lock = threading.RLock()
def __init__(self, source_model: LogFileModel): def __init__(self, source_model: LogFileModel):
super(FilterWidget, self).__init__() super(FilterWidget, self).__init__()
@@ -60,6 +71,10 @@ class FilterWidget(QWidget):
self.query_field = QLineEdit() self.query_field = QLineEdit()
self.query_field.textChanged.connect(self.filter_changed) self.query_field.textChanged.connect(self.filter_changed)
self.btn_cancel_search = QPushButton(self.tr("Cancel"))
self.btn_cancel_search.setVisible(False)
self.btn_cancel_search.pressed.connect(self._cancel_search)
self.ignore_case = QCheckBox(self.tr("ignore case")) self.ignore_case = QCheckBox(self.tr("ignore case"))
self.ignore_case.setChecked(True) self.ignore_case.setChecked(True)
self.ignore_case.stateChanged.connect(self.filter_changed) self.ignore_case.stateChanged.connect(self.filter_changed)
@@ -72,6 +87,7 @@ class FilterWidget(QWidget):
filter_bar.layout = QHBoxLayout(filter_bar) filter_bar.layout = QHBoxLayout(filter_bar)
filter_bar.layout.setContentsMargins(0, 0, 0, 0) filter_bar.layout.setContentsMargins(0, 0, 0, 0)
filter_bar.layout.addWidget(self.query_field) filter_bar.layout.addWidget(self.query_field)
filter_bar.layout.addWidget(self.btn_cancel_search)
filter_bar.layout.addWidget(self.ignore_case) filter_bar.layout.addWidget(self.ignore_case)
filter_bar.layout.addWidget(self.is_regex) filter_bar.layout.addWidget(self.is_regex)
@@ -83,9 +99,14 @@ class FilterWidget(QWidget):
self.layout.addWidget(self.hits_view) self.layout.addWidget(self.hits_view)
def destruct(self): def destruct(self):
print("cleanup: ", self.tmpfilename) #print("cleanup: ", self.tmpfilename)
os.remove(self.tmpfilename) os.remove(self.tmpfilename)
def _cancel_search(self):
if self.filter_task:
#print("cancel started ", time.time())
self.filter_task.aborted = True
def filter_changed(self): def filter_changed(self):
query = self.query_field.text() query = self.query_field.text()
ignore_case = self.ignore_case.isChecked() ignore_case = self.ignore_case.isChecked()
@@ -93,8 +114,8 @@ class FilterWidget(QWidget):
if len(query) == 0: if len(query) == 0:
return return
if self.filter_task: # cancel previous search
self.filter_task.aborted = True self._cancel_search()
try: try:
flags = re.IGNORECASE if ignore_case else 0 flags = re.IGNORECASE if ignore_case else 0
@@ -106,5 +127,15 @@ class FilterWidget(QWidget):
# query was not a valid regex -> abort # query was not a valid regex -> abort
return return
self.filter_task = FilterTask(self.source_model, self.filter_model, regex)
self.filter_task = FilterTask(
self.source_model,
self.filter_model,
regex,
self._lock,
lambda : self.btn_cancel_search.setVisible(True),
lambda : self.btn_cancel_search.setVisible(False)
)
QThreadPool.globalInstance().start(self.filter_task) QThreadPool.globalInstance().start(self.filter_task)