add cancel button
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user