diff --git a/bigtext.py b/bigtext.py index 8d6d7a9..679a73d 100644 --- a/bigtext.py +++ b/bigtext.py @@ -93,7 +93,7 @@ class InnerBigText(QWidget): self.scroll_by_lines(-3) def wheelEvent(self, event: QWheelEvent): - direction = 1 if event.angleDelta().y() > 0 else -1 + direction = 1 if event.angleDelta().y() < 0 else -1 #print("wheel event fired :) %s" % (direction)) self.scroll_by_lines(direction * 3) @@ -164,9 +164,9 @@ class InnerBigText(QWidget): self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show) #print("lines_to_show: %d returned: %d" % (lines_to_show, len(self.lines))) self.scroll_lines=0 - self._byte_offset = self.lines[0].byte_offset() + self._byte_offset = self.lines[0].byte_offset() if len(self.lines) > 0 else 0 # document length == maximum + pageStep + aFewBytesSoThatTheLastLineIsShown - self.parent.v_scroll_bar.setMaximum(self.model.byte_count() - 1 - 10) + self.parent.v_scroll_bar.setMaximum(self.model.byte_count() - 1) for l in self.lines: diff --git a/line.py b/line.py index c931dd4..e67a040 100644 --- a/line.py +++ b/line.py @@ -31,4 +31,7 @@ class Line: return self._line[offset:offset+length] def suffix(self, index: int) -> str: - return self._line[index:] \ No newline at end of file + return self._line[index:] + + def __str__(self): + return "%s (%d->%d)" % (self._line, self._byte_offset, self._byte_end) \ No newline at end of file diff --git a/logFileModel.py b/logFileModel.py index 60be188..b5c3dfb 100644 --- a/logFileModel.py +++ b/logFileModel.py @@ -1,8 +1,8 @@ +import math import threading from typing import List -import os from line import Line - +import os from settings import Settings @@ -13,11 +13,12 @@ class LogFileModel: self._file = file def data(self, byte_offset, scroll_lines, lines) -> List[Line]: - #print("data(%s, %s, %s)" % (byte_offset, scroll_lines, lines)) + 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 + abs(scroll_lines) + lines_to_return = math.ceil(lines) with self._lock: # TODO handle lines longer than 4096 bytes @@ -42,18 +43,12 @@ class LogFileModel: 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 + all_lines = lines_before_offset + lines_after_offset + start = max(0, len(lines_before_offset) + scroll_lines) + if start + lines_to_return-1 < len(all_lines): + result = all_lines[start:start+lines_to_return] else: - result = result + lines_after_offset[-scroll_lines:] + result = all_lines[-lines_to_return+1:] #print("returning %s lines" % (len(result))) return result diff --git a/scribble.py b/scribble.py new file mode 100644 index 0000000..83e219f --- /dev/null +++ b/scribble.py @@ -0,0 +1,15 @@ +import math + + + +before = []#[0,1,2,3] +after = ["a","b","c","d"] +both = before + after +scroll = -3 +lines = 1 +start = len(before) + scroll +if start+lines < len(both): + result = both[start:start+lines] +else: + result = both[-lines:] +print("%s" % result) diff --git a/testlogfilemodel.py b/testlogfilemodel.py new file mode 100644 index 0000000..3305e81 --- /dev/null +++ b/testlogfilemodel.py @@ -0,0 +1,142 @@ +import unittest +import tempfile +from os.path import join + +from logFileModel import LogFileModel +from line import Line + + +class TestLogFileModel(unittest.TestCase): + + def setUp(self): + self.test_dir = tempfile.TemporaryDirectory() + self.tmpfile = join(self.test_dir.name, "my.log") + self.model = LogFileModel(self.tmpfile) + + def tearDown(self): + self.test_dir.cleanup() + + def write_str(self, string: str): + with open(self.tmpfile, "w+b") as f: + f.write(string.encode("utf8")) + + def test_load_from_beginning(self): + self.write_str("1\n2\n3\n4\n5\n6\n7\n") + expected_lines = ["1", "2", "3", "4", "5"] + + lines = self.model.data(0, 0, 5) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + def test_load_from_middle_of_first_line(self): + self.write_str("abc\ndef\nghi\njkl") + expected_lines = ["def", "ghi", "jkl"] + + lines = self.model.data(1, 0, 3) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + def test_read_from_newline_character(self): + self.write_str("abc\ndef\nghi\njkl") + expected_lines = ["def", "ghi"] + + lines = self.model.data(3, 0, 2) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + + def test_negative_byte_offset(self): + self.write_str("abc\ndef\nghi\njkl") + expected_lines = ["abc","def"] + + lines = self.model.data(-1, 0, 2) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + def test_empty_last_line_is_ignored(self): + self.write_str("1\n") + expected_lines = ["1"] + + lines = self.model.data(0, 0, 5) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + def test_load_more_lines_than_are_available(self): + """ + Wants to read 4 lines in a file with only 3 lines. + Returns all three lines. + """ + self.write_str("abc\ndef\nghi") + expected_lines = ["abc", "def", "ghi"] + + lines = self.model.data(0, 0, 4) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + def test_read_behind_eof(self): + """ + Wants to read 4 lines from the middle of the second line. + File has only 3 lines. + Returns all 3 lines. + """ + text = "abc\ndef\nghi" + self.write_str(text) + expected_lines = ["abc", "def", "ghi"] + + lines = self.model.data(text.index("e"), 0, 4) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + def test_read_after_scrolling_2_lines(self): + """ + + """ + text = "0___\n1___\n2___\n3___\n4___\n5___" + self.write_str(text) + expected_lines = ["3___", "4___"] + + lines = self.model.data(text.index("1___"), 2, 2) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + + def test_scroll_with_float(self): + """ + If lines to lines to return is a float, then the value is rounded up. + Floats mean that the text area is such that a line is partially visible. + """ + text = "0___\n1___\n2___\n3___\n4___\n5___" + self.write_str(text) + expected_lines = ["3___","4___", "5___"] + + lines = self.model.data(text.index("1___"), 2, 2.1) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + + + def test_scroll_up_at_beginning_of_file(self): + """ + Scrolling up at beginning of file. + Return + """ + text = "0___\n1___\n2___\n3___\n4___\n5___" + self.write_str(text) + expected_lines = ["0___", "1___"] + + lines = self.model.data(5, -2, 2) + + line_str = [l.line() for l in lines] + self.assertEqual(expected_lines, line_str) + +if __name__ == '__main__': + unittest.main() +