intermediate state after fixing the logfilemodel test

This commit is contained in:
2022-12-17 10:06:15 +01:00
parent 5df0dc0c82
commit a06a2d01f3
5 changed files with 87 additions and 38 deletions

View File

@@ -180,7 +180,7 @@ class FilterWidget(QWidget):
(handle, self.tmp_filename) = tempfile.mkstemp() (handle, self.tmp_filename) = tempfile.mkstemp()
os.close(handle) os.close(handle)
self.filter_model = LogFileModel(self.tmp_filename, self.source_model.settings) self.filter_model = LogFileModel(self.tmp_filename, self.source_model.settings)
self.hits_view = BigText(self.filter_model) self.hits_view = BigText(self.filter_model, show_range_slider=False)
self.layout.addWidget(filter_bar) self.layout.addWidget(filter_bar)
self.layout.addWidget(self.hits_view) self.layout.addWidget(self.hits_view)

View File

@@ -10,6 +10,9 @@ log = logging.getLogger("scaledScrollBar")
class ScaledScrollBar(QScrollBar): class ScaledScrollBar(QScrollBar):
is_huge = False is_huge = False
_range_start = 0;
_range_end = -1
scaledValueChanged = Signal(str) scaledValueChanged = Signal(str)
"""Signal emitted when the scroll bar value changes. """Signal emitted when the scroll bar value changes.
**Note**: The value is a string and must be parsed into an int. **Note**: The value is a string and must be parsed into an int.
@@ -26,12 +29,32 @@ class ScaledScrollBar(QScrollBar):
self.real_maximum = self.maximum() self.real_maximum = self.maximum()
super().valueChanged.connect(self._valueChanged) super().valueChanged.connect(self._valueChanged)
def set_range(self, range_start: int, range_end: int):
old_range_start = self._range_start
self._range_start = range_start
self._range_end = range_end
new_max = range_end - range_start
old_value = self._real_value()
new_value = old_value - range_start
self.setMaximum(new_max)
self.setValue(new_value)
print(f"old_value: {old_value} new_value {new_value}")
def setValue(self, value: int) -> None: def setValue(self, value: int) -> None:
if self.is_huge: if self.is_huge:
real_position = value / self.real_maximum real_position = value / self.real_maximum
super().setValue(round(self.maximum() * real_position)) super().setValue(round(self.maximum() * real_position))
else: else:
super().setValue(value) super().setValue(value - self._range_start)
def _real_value(self):
value = self.value()
if self.is_huge:
real_value = self._range_start + (value / self.maximum()) * self.real_maximum
# print("scaled value changed: %d -> %d (%f)" % (value, real_value, value / self.maximum()))
return int(real_value)
else:
return int(self._range_start + value)
def setMaximum(self, maximum: int) -> None: def setMaximum(self, maximum: int) -> None:
if maximum > 2 ** 31: if maximum > 2 ** 31:
@@ -50,9 +73,4 @@ class ScaledScrollBar(QScrollBar):
def _valueChanged(self, value: int): def _valueChanged(self, value: int):
self.scrolled_to_end.emit(value == self.maximum() and value > 0) self.scrolled_to_end.emit(value == self.maximum() and value > 0)
if self.is_huge: self.scaledValueChanged.emit(str(self._real_value()))
real_value = (value / self.maximum()) * self.real_maximum
# print("scaled value changed: %d -> %d (%f)" % (value, real_value, value / self.maximum()))
self.scaledValueChanged.emit(str(int(real_value)))
else:
self.scaledValueChanged.emit(str(int(value)))

View File

@@ -17,6 +17,7 @@ from src.ui.bigtext.highlightingdialog import HighlightingDialog
from src.ui.bigtext.line import Line from src.ui.bigtext.line import Line
from src.ui.bigtext.logFileModel import LogFileModel from src.ui.bigtext.logFileModel import LogFileModel
from src.ui.icon import Icon from src.ui.icon import Icon
from src.ui.rangeslider import RangeSlider
from src.util.conversion import humanbytes from src.util.conversion import humanbytes
from src.pluginregistry import PluginRegistry from src.pluginregistry import PluginRegistry
@@ -61,7 +62,7 @@ class FileWatchdogThread(QRunnable):
class BigText(QWidget): class BigText(QWidget):
trigger_update = Signal() trigger_update = Signal()
def __init__(self, model: LogFileModel): def __init__(self, model: LogFileModel, show_range_slider=True):
super(BigText, self).__init__() super(BigText, self).__init__()
self.model = model self.model = model
@@ -85,14 +86,27 @@ class BigText(QWidget):
self.v_scroll_bar.scaledValueChanged.connect(self.big_text.v_scroll_event) self.v_scroll_bar.scaledValueChanged.connect(self.big_text.v_scroll_event)
self.v_scroll_bar.scrolled_to_end.connect(self.big_text.v_scroll_update_follow_tail) self.v_scroll_bar.scrolled_to_end.connect(self.big_text.v_scroll_update_follow_tail)
self.grid.addWidget(self.big_text, 0, 0) self.range_limit = RangeSlider()
self.grid.addWidget(self.h_scroll_bar, 1, 0) self.range_limit.value_changed.connect(self._range_limit_event)
self.grid.addWidget(self.v_scroll_bar, 0, 1)
if show_range_slider:
self.grid.addWidget(self.range_limit, 0, 0)
self.grid.addWidget(self.big_text, 0, 1)
self.grid.addWidget(self.h_scroll_bar, 1, 1)
self.grid.addWidget(self.v_scroll_bar, 0, 2)
self.watchdog = FileWatchdogThread(self, model.get_file()) self.watchdog = FileWatchdogThread(self, model.get_file())
QThreadPool.globalInstance().start(self.watchdog) QThreadPool.globalInstance().start(self.watchdog)
self.trigger_update.connect(self.big_text._file_changed) self.trigger_update.connect(self.big_text._file_changed)
def _range_limit_event(self, lower_value: float, upper_value: float):
byte_count = self.model.byte_count()
range_start = int(byte_count * (lower_value / 100.0))
range_end = int(byte_count * (upper_value / 100.0))
print(f"-> {lower_value}, {upper_value}, {range_start}, {range_end}")
self.v_scroll_bar.set_range(range_start, range_end)
self.big_text.set_range(range_start, range_end)
def get_file(self): def get_file(self):
return self.model.get_file() return self.model.get_file()
@@ -121,6 +135,9 @@ class InnerBigText(QWidget):
scroll_lines = 0 scroll_lines = 0
longest_line = 0 longest_line = 0
_range_start = 0
_range_end = -1
def __init__(self, parent: BigText, model: LogFileModel): def __init__(self, parent: BigText, model: LogFileModel):
super(InnerBigText, self).__init__() super(InnerBigText, self).__init__()
self.char_height = None self.char_height = None
@@ -148,6 +165,15 @@ class InnerBigText(QWidget):
self.line_click_listeners: [Callable[[int], None]] = [] self.line_click_listeners: [Callable[[int], None]] = []
def set_range(self, range_start: int, range_end: int):
self._range_start = range_start
self._range_end = range_end
self._set_byte_offset(self._byte_offset)
def _set_byte_offset(self, byte_offset: int):
self._byte_offset = min(max(byte_offset, self._range_start), self._range_end)
self.update()
def clear_selection_highlight(self): def clear_selection_highlight(self):
self.selection_highlight.start_byte = 0 self.selection_highlight.start_byte = 0
self.selection_highlight.end_byte = 0 self.selection_highlight.end_byte = 0
@@ -432,7 +458,8 @@ class InnerBigText(QWidget):
lines_to_show = math.ceil(self.lines_shown()) lines_to_show = math.ceil(self.lines_shown())
# print("%s / %s = %s" %(self.height(), float(self.char_height), lines_to_show)) # print("%s / %s = %s" %(self.height(), float(self.char_height), lines_to_show))
self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show) self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show, self._range_start,
self._range_end)
# print("lines_to_show: %d returned: %d" % (lines_to_show, len(self.lines))) # print("lines_to_show: %d returned: %d" % (lines_to_show, len(self.lines)))
self.scroll_lines = 0 self.scroll_lines = 0
self._byte_offset = self.lines[0].byte_offset() if len(self.lines) > 0 else 0 self._byte_offset = self.lines[0].byte_offset() if len(self.lines) > 0 else 0

View File

@@ -73,7 +73,7 @@ class LogFileModel:
offset = new_offset offset = new_offset
def read_word_at(self, byte_offset: int) -> (str, int, int): def read_word_at(self, byte_offset: int) -> (str, int, int):
lines = self.data(byte_offset, 0, 1) lines = self.data(byte_offset, 0, 1, 0, -1)
if len(lines) == 0: if len(lines) == 0:
return "", -1, -1 return "", -1, -1
line: Line = lines[0] line: Line = lines[0]
@@ -99,7 +99,7 @@ class LogFileModel:
def _is_word_char(self, char: str) -> bool: def _is_word_char(self, char: str) -> bool:
return re.match(r"\w", char) is not None return re.match(r"\w", char) is not None
def data(self, byte_offset: int, scroll_lines: int, lines: int) -> List[Line]: def data(self, byte_offset: int, scroll_lines: int, lines: int, range_start: int, range_end: int) -> 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_before_offset: List[Line] = []
lines_after_offset: List[Line] = [] lines_after_offset: List[Line] = []
@@ -107,19 +107,23 @@ class LogFileModel:
lines_to_return = math.ceil(lines) lines_to_return = math.ceil(lines)
# TODO handle lines longer than 4096 bytes # TODO handle lines longer than 4096 bytes
# TODO abort file open after a few secons: https://docs.python.org/3/library/signal.html#example # TODO abort file open after a few seconds: https://docs.python.org/3/library/signal.html#example
with open(self._file, 'rb') as f: with open(self._file, 'rb') as f:
offset = min(byte_offset, self.byte_count()) offset = min(byte_offset, self.byte_count())
# print("offset: %s byte_count: %d" % (offset, self.byte_count())) # print("offset: %s byte_count: %d" % (offset, self.byte_count()))
offset = max(0, offset - self.settings.max_line_length()) offset = max(0,
max(range_start - self.settings.max_line_length(), offset - self.settings.max_line_length()))
f.seek(offset) f.seek(offset)
while l := f.readline(): while l := f.readline():
new_offset = f.tell() new_offset = f.tell()
if 0 <= range_end < new_offset:
break
line = Line(offset, new_offset, l.decode("utf8", errors="ignore")) line = Line(offset, new_offset, l.decode("utf8", errors="ignore"))
if line.byte_end() <= byte_offset: # line.byte_end() returns the end byte +1 if line.byte_end() <= byte_offset: # line.byte_end() returns the end byte +1
lines_before_offset.append(line) if line.byte_offset() >= range_start: # only add if in range
lines_before_offset.append(line)
else: else:
lines_after_offset.append(line) lines_after_offset.append(line)
offset = f.tell() offset = f.tell()

View File

@@ -23,27 +23,27 @@ class TestLogFileModel(unittest.TestCase):
def test_load_from_beginning(self): def test_load_from_beginning(self):
self.write_str("1\n2\n3\n4\n5\n6\n7\n") self.write_str("1\n2\n3\n4\n5\n6\n7\n")
expected_lines = ["1", "2", "3", "4", "5"] expected_lines = ["1\n", "2\n", "3\n", "4\n", "5\n"]
lines = self.model.data(0, 0, 5) lines = self.model.data(0, 0, 5, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
def test_load_from_middle_of_first_line(self): def test_load_from_middle_of_first_line(self):
self.write_str("abc\ndef\nghi\njkl") self.write_str("abc\ndef\nghi\njkl")
expected_lines = ["abc", "def", "ghi"] expected_lines = ["abc\n", "def\n", "ghi\n"]
lines = self.model.data(1, 0, 3) lines = self.model.data(1, 0, 3, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
def test_read_from_newline_character(self): def test_read_from_newline_character(self):
self.write_str("abc\ndef\nghi\njkl") self.write_str("abc\ndef\nghi\njkl")
expected_lines = ["abc", "def"] expected_lines = ["abc\n", "def\n"]
lines = self.model.data(3, 0, 2) lines = self.model.data(3, 0, 2, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
@@ -51,18 +51,18 @@ class TestLogFileModel(unittest.TestCase):
def test_negative_byte_offset(self): def test_negative_byte_offset(self):
self.write_str("abc\ndef\nghi\njkl") self.write_str("abc\ndef\nghi\njkl")
expected_lines = ["abc","def"] expected_lines = ["abc\n", "def\n"]
lines = self.model.data(-1, 0, 2) lines = self.model.data(-1, 0, 2, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
def test_empty_last_line_is_ignored(self): def test_empty_last_line_is_ignored(self):
self.write_str("1\n") self.write_str("1\n")
expected_lines = ["1"] expected_lines = ["1\n"]
lines = self.model.data(0, 0, 5) lines = self.model.data(0, 0, 5, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
@@ -73,9 +73,9 @@ class TestLogFileModel(unittest.TestCase):
Returns all three lines. Returns all three lines.
""" """
self.write_str("abc\ndef\nghi") self.write_str("abc\ndef\nghi")
expected_lines = ["abc", "def", "ghi"] expected_lines = ["abc\n", "def\n", "ghi"]
lines = self.model.data(0, 0, 4) lines = self.model.data(0, 0, 4, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
@@ -88,9 +88,9 @@ class TestLogFileModel(unittest.TestCase):
""" """
text = "abc\ndef\nghi" text = "abc\ndef\nghi"
self.write_str(text) self.write_str(text)
expected_lines = ["abc", "def", "ghi"] expected_lines = ["abc\n", "def\n", "ghi"]
lines = self.model.data(text.index("e"), 0, 4) lines = self.model.data(text.index("e"), 0, 4, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
@@ -101,9 +101,9 @@ class TestLogFileModel(unittest.TestCase):
""" """
text = "0___\n1___\n2___\n3___\n4___\n5___" text = "0___\n1___\n2___\n3___\n4___\n5___"
self.write_str(text) self.write_str(text)
expected_lines = ["3___", "4___"] expected_lines = ["3___\n", "4___\n"]
lines = self.model.data(text.index("1___"), 2, 2) lines = self.model.data(text.index("1___"), 2, 2, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
@@ -116,9 +116,9 @@ class TestLogFileModel(unittest.TestCase):
""" """
text = "0___\n1___\n2___\n3___\n4___\n5___" text = "0___\n1___\n2___\n3___\n4___\n5___"
self.write_str(text) self.write_str(text)
expected_lines = ["3___","4___", "5___"] expected_lines = ["3___\n", "4___\n", "5___"]
lines = self.model.data(text.index("1___"), 2, 2.1) lines = self.model.data(text.index("1___"), 2, 2.1, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)
@@ -131,9 +131,9 @@ class TestLogFileModel(unittest.TestCase):
""" """
text = "0___\n1___\n2___\n3___\n4___\n5___" text = "0___\n1___\n2___\n3___\n4___\n5___"
self.write_str(text) self.write_str(text)
expected_lines = ["0___", "1___"] expected_lines = ["0___\n", "1___\n"]
lines = self.model.data(5, -2, 2) lines = self.model.data(5, -2, 2, 0, -1)
line_str = [l.line() for l in lines] line_str = [l.line() for l in lines]
self.assertEqual(expected_lines, line_str) self.assertEqual(expected_lines, line_str)