From b99fb35727812fd8079589af6730ca4c09435c01 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 24 Oct 2021 20:02:11 +0200 Subject: [PATCH] scroll by wheel --- bigtext.py | 13 ++++++++++- logFileModel.py | 62 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/bigtext.py b/bigtext.py index 4212cf0..b3afda2 100644 --- a/bigtext.py +++ b/bigtext.py @@ -20,6 +20,7 @@ from settings import Settings class BigText(QWidget): _byte_offset = 0 _left_offset = 0 + scroll_lines = 0 highlights: [Highlight] = [] @@ -42,6 +43,14 @@ class BigText(QWidget): def paintEvent(self, event: QPaintEvent) -> None: self.draw() + def wheelEvent(self, event: QWheelEvent): + direction = 1 if event.angleDelta().y() > 0 else -1 + #print("wheel event fired :) %s" % (direction)) + self.scroll_lines = direction * 3 + self.update() + #self.draw(direction * 3) + #self._vscrollbar.setValue(self._byte_offset) + def mousePressEvent(self, e: QMouseEvent) -> None: if e.buttons() == Qt.MouseButton.LeftButton: offset = self.to_byte_offset(e) @@ -80,7 +89,9 @@ class BigText(QWidget): self.update_font_metrics(painter) lines_to_show = self.height() / (self.fontMetrics().height()) - self.lines = self.model.data(self._byte_offset, lines_to_show) + self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show) + self.scroll_lines=0 + self._byte_offset = self.lines[0].byte_offset() # draw hightlights first - some characters may overlap to the next line # by drawing the background hightlights first we prevent that the hightlight diff --git a/logFileModel.py b/logFileModel.py index 2594cd4..ab0139b 100644 --- a/logFileModel.py +++ b/logFileModel.py @@ -1,3 +1,4 @@ +import threading from typing import List import os from line import Line @@ -6,27 +7,56 @@ from settings import Settings class LogFileModel: + _lock = threading.RLock() + def __init__(self, file): self._file = file - def data(self, byte_offset:int, lines: int) -> List[Line]: - result : List[Line] = [] + def data(self, byte_offset, scroll_lines, lines) -> List[Line]: + #print("data(%s, %s, %s)" % (byte_offset, scroll_lines, lines)) + lines_before_offset: List[Line] = [] + lines_after_offset: List[Line] = [] + result: List[Line] = [] + lines_to_find = lines # + -1 * scroll_lines - # TODO handle lines longer than 4096 bytes - with open(self._file, 'r') as f: - offset = max(0, byte_offset - Settings.max_line_length()) - offset = offset - offset % Settings.max_line_length() # align to blocks of 4kb - f.seek(offset) - while l := f.readline(): - new_offset = f.tell() - if offset >= byte_offset: - line = Line(offset, new_offset-1, l) - result.append(line) - offset = new_offset - if len(result) >= lines: - break + with self._lock: + # TODO handle lines longer than 4096 bytes + with open(self._file, 'rb') as f: + offset = min(byte_offset, self.byte_count()) + offset = max(0, offset - Settings.max_line_length()) - return result + #print("offset: %s" % (offset)) + + eof_reached = True + f.seek(offset) + while l := f.readline(): + new_offset = f.tell() + line = Line(offset, new_offset, l.decode("utf8").replace("\r", "").replace("\n", "")) + # print("%s %s" %(line.byte_offset(), line.line())) + if offset < byte_offset: + lines_before_offset.append(line) + else: + lines_after_offset.append(line) + offset = f.tell() + if len(lines_after_offset) >= lines_to_find: + eof_reached = False + break + + if scroll_lines > 0: + result = result + lines_before_offset[-scroll_lines:] + result = result + lines_after_offset + elif eof_reached: + # we always return the number of requested lines even if we reach the end of the file + lines_to_return_from_before_offset = int(lines_to_find - len(lines_after_offset)); + print(lines_to_return_from_before_offset) + if lines_to_return_from_before_offset > 0: + result = result + lines_before_offset[-lines_to_return_from_before_offset:] + result = result + lines_after_offset + else: + result = result + lines_after_offset[-scroll_lines:] + + #print("returning %s lines" % (len(result))) + return result def byte_count(self) -> int: return os.stat(self._file).st_size \ No newline at end of file