intermediate state after fixing the logfilemodel test
This commit is contained in:
@@ -180,7 +180,7 @@ class FilterWidget(QWidget):
|
||||
(handle, self.tmp_filename) = tempfile.mkstemp()
|
||||
os.close(handle)
|
||||
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(self.hits_view)
|
||||
|
||||
@@ -10,6 +10,9 @@ log = logging.getLogger("scaledScrollBar")
|
||||
class ScaledScrollBar(QScrollBar):
|
||||
is_huge = False
|
||||
|
||||
_range_start = 0;
|
||||
_range_end = -1
|
||||
|
||||
scaledValueChanged = Signal(str)
|
||||
"""Signal emitted when the scroll bar value changes.
|
||||
**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()
|
||||
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:
|
||||
if self.is_huge:
|
||||
real_position = value / self.real_maximum
|
||||
super().setValue(round(self.maximum() * real_position))
|
||||
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:
|
||||
if maximum > 2 ** 31:
|
||||
@@ -50,9 +73,4 @@ class ScaledScrollBar(QScrollBar):
|
||||
|
||||
def _valueChanged(self, value: int):
|
||||
self.scrolled_to_end.emit(value == self.maximum() and value > 0)
|
||||
if self.is_huge:
|
||||
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)))
|
||||
self.scaledValueChanged.emit(str(self._real_value()))
|
||||
|
||||
@@ -17,6 +17,7 @@ from src.ui.bigtext.highlightingdialog import HighlightingDialog
|
||||
from src.ui.bigtext.line import Line
|
||||
from src.ui.bigtext.logFileModel import LogFileModel
|
||||
from src.ui.icon import Icon
|
||||
from src.ui.rangeslider import RangeSlider
|
||||
from src.util.conversion import humanbytes
|
||||
from src.pluginregistry import PluginRegistry
|
||||
|
||||
@@ -61,7 +62,7 @@ class FileWatchdogThread(QRunnable):
|
||||
class BigText(QWidget):
|
||||
trigger_update = Signal()
|
||||
|
||||
def __init__(self, model: LogFileModel):
|
||||
def __init__(self, model: LogFileModel, show_range_slider=True):
|
||||
super(BigText, self).__init__()
|
||||
|
||||
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.scrolled_to_end.connect(self.big_text.v_scroll_update_follow_tail)
|
||||
|
||||
self.grid.addWidget(self.big_text, 0, 0)
|
||||
self.grid.addWidget(self.h_scroll_bar, 1, 0)
|
||||
self.grid.addWidget(self.v_scroll_bar, 0, 1)
|
||||
self.range_limit = RangeSlider()
|
||||
self.range_limit.value_changed.connect(self._range_limit_event)
|
||||
|
||||
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())
|
||||
QThreadPool.globalInstance().start(self.watchdog)
|
||||
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):
|
||||
return self.model.get_file()
|
||||
|
||||
@@ -121,6 +135,9 @@ class InnerBigText(QWidget):
|
||||
scroll_lines = 0
|
||||
longest_line = 0
|
||||
|
||||
_range_start = 0
|
||||
_range_end = -1
|
||||
|
||||
def __init__(self, parent: BigText, model: LogFileModel):
|
||||
super(InnerBigText, self).__init__()
|
||||
self.char_height = None
|
||||
@@ -148,6 +165,15 @@ class InnerBigText(QWidget):
|
||||
|
||||
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):
|
||||
self.selection_highlight.start_byte = 0
|
||||
self.selection_highlight.end_byte = 0
|
||||
@@ -432,7 +458,8 @@ class InnerBigText(QWidget):
|
||||
lines_to_show = math.ceil(self.lines_shown())
|
||||
# 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)))
|
||||
self.scroll_lines = 0
|
||||
self._byte_offset = self.lines[0].byte_offset() if len(self.lines) > 0 else 0
|
||||
|
||||
@@ -73,7 +73,7 @@ class LogFileModel:
|
||||
offset = new_offset
|
||||
|
||||
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:
|
||||
return "", -1, -1
|
||||
line: Line = lines[0]
|
||||
@@ -99,7 +99,7 @@ class LogFileModel:
|
||||
def _is_word_char(self, char: str) -> bool:
|
||||
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))
|
||||
lines_before_offset: List[Line] = []
|
||||
lines_after_offset: List[Line] = []
|
||||
@@ -107,18 +107,22 @@ class LogFileModel:
|
||||
lines_to_return = math.ceil(lines)
|
||||
|
||||
# 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:
|
||||
offset = min(byte_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)
|
||||
while l := f.readline():
|
||||
new_offset = f.tell()
|
||||
if 0 <= range_end < new_offset:
|
||||
break
|
||||
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_offset() >= range_start: # only add if in range
|
||||
lines_before_offset.append(line)
|
||||
else:
|
||||
lines_after_offset.append(line)
|
||||
|
||||
@@ -23,27 +23,27 @@ class TestLogFileModel(unittest.TestCase):
|
||||
|
||||
def test_load_from_beginning(self):
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
|
||||
def test_load_from_middle_of_first_line(self):
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
|
||||
def test_read_from_newline_character(self):
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
@@ -51,18 +51,18 @@ class TestLogFileModel(unittest.TestCase):
|
||||
|
||||
def test_negative_byte_offset(self):
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
|
||||
def test_empty_last_line_is_ignored(self):
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
@@ -73,9 +73,9 @@ class TestLogFileModel(unittest.TestCase):
|
||||
Returns all three lines.
|
||||
"""
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
@@ -88,9 +88,9 @@ class TestLogFileModel(unittest.TestCase):
|
||||
"""
|
||||
text = "abc\ndef\nghi"
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
@@ -101,9 +101,9 @@ class TestLogFileModel(unittest.TestCase):
|
||||
"""
|
||||
text = "0___\n1___\n2___\n3___\n4___\n5___"
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
@@ -116,9 +116,9 @@ class TestLogFileModel(unittest.TestCase):
|
||||
"""
|
||||
text = "0___\n1___\n2___\n3___\n4___\n5___"
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
@@ -131,9 +131,9 @@ class TestLogFileModel(unittest.TestCase):
|
||||
"""
|
||||
text = "0___\n1___\n2___\n3___\n4___\n5___"
|
||||
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]
|
||||
self.assertEqual(expected_lines, line_str)
|
||||
|
||||
Reference in New Issue
Block a user