feature: follow the file and show always the end when new data comes

This commit is contained in:
2025-03-24 19:20:49 +01:00
parent 61132d242f
commit 9902be0a48
7 changed files with 111 additions and 58 deletions

View File

@@ -5,8 +5,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: RavenLog\n" "Project-Id-Version: RavenLog\n"
"POT-Creation-Date: 2024-03-24 12:00+0100\n" "POT-Creation-Date: 2025-03-24 19:02+0100\n"
"PO-Revision-Date: 2024-03-24 12:02+0100\n" "PO-Revision-Date: 2025-03-24 19:17+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"Language: de\n" "Language: de\n"
@@ -15,10 +15,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 3.0.1\n" "X-Generator: Poedit 3.5\n"
#: src/mainwindow.py:32 src/plugins/krowlog/aboutdialog.py:30 #: src/mainwindow.py:32 src/new_big_text/bigger_text.py:75
#: src/plugins/krowlogplugin.py:85 #: src/plugins/krowlog/aboutdialog.py:30 src/plugins/krowlogplugin.py:85
msgid "KrowLog" msgid "KrowLog"
msgstr "KrowLog" msgstr "KrowLog"
@@ -146,31 +146,31 @@ msgstr "&Über KrowLog"
msgid "E&xit" msgid "E&xit"
msgstr "&Beenden" msgstr "&Beenden"
#: src/plugins/logfile/filterwidget.py:181 #: src/plugins/logfile/filterwidget.py:192
msgid "Cancel" msgid "Cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: src/plugins/logfile/filterwidget.py:187 #: src/plugins/logfile/filterwidget.py:198
msgid "save query" msgid "save query"
msgstr "suche speichern" msgstr "suche speichern"
#: src/plugins/logfile/filterwidget.py:192 #: src/plugins/logfile/filterwidget.py:203
msgid "ignore case" msgid "ignore case"
msgstr "Groß-/Kleinschreibung ignorieren" msgstr "Groß-/Kleinschreibung ignorieren"
#: src/plugins/logfile/filterwidget.py:196 #: src/plugins/logfile/filterwidget.py:207
msgid "regex" msgid "regex"
msgstr "RegExp" msgstr "RegExp"
#: src/plugins/logfile/filterwidget.py:206 #: src/plugins/logfile/filterwidget.py:217
msgid "only matches" msgid "only matches"
msgstr "nur Treffer" msgstr "nur Treffer"
#: src/plugins/logfile/filterwidget.py:298 #: src/plugins/logfile/filterwidget.py:309
msgid "({hits} lines)" msgid "({hits} lines)"
msgstr "({hits} Zeilen)" msgstr "({hits} Zeilen)"
#: src/plugins/logfileplugin.py:35 src/ui/bigtext/bigtext.py:258 #: src/plugins/logfileplugin.py:35 src/ui/bigtext/bigtext.py:263
msgid "&Highlighter" msgid "&Highlighter"
msgstr "&Hervorhebungen" msgstr "&Hervorhebungen"
@@ -200,65 +200,69 @@ msgstr "Öffne Datei"
#: src/plugins/timediff/time_diff_menu_widget.py:32 #: src/plugins/timediff/time_diff_menu_widget.py:32
msgid "ms" msgid "ms"
msgstr "" msgstr "ms"
#: src/plugins/timediff/time_diff_menu_widget.py:33 #: src/plugins/timediff/time_diff_menu_widget.py:33
msgid "s" msgid "s"
msgstr "" msgstr "s"
#: src/plugins/timediff/time_diff_menu_widget.py:34 #: src/plugins/timediff/time_diff_menu_widget.py:34
msgid "m" msgid "m"
msgstr "" msgstr "m"
#: src/plugins/timediff/time_diff_menu_widget.py:35 #: src/plugins/timediff/time_diff_menu_widget.py:35
msgid "h" msgid "h"
msgstr "" msgstr "h"
#: src/ui/bigtext/bigtext.py:238 #: src/ui/bigtext/bigtext.py:243
msgid "&Copy to Clipboard" msgid "&Copy to Clipboard"
msgstr "In Zwischenablage &Kopieren" msgstr "In Zwischenablage &Kopieren"
#: src/ui/bigtext/bigtext.py:246 #: src/ui/bigtext/bigtext.py:251
msgid "Copy to &File" msgid "Copy to &File"
msgstr "In &Datei Kopieren" msgstr "In &Datei Kopieren"
#: src/ui/bigtext/bigtext.py:252 #: src/ui/bigtext/bigtext.py:257
msgid "Select &All" msgid "Select &All"
msgstr "&Alles Selektieren" msgstr "&Alles Selektieren"
#: src/ui/bigtext/bigtext.py:268 #: src/ui/bigtext/bigtext.py:270
msgid "&Follow"
msgstr "&Folgen"
#: src/ui/bigtext/bigtext.py:280
msgid "Set Range Start" msgid "Set Range Start"
msgstr "Setze Start des Anzeigebereichs" msgstr "Setze Start des Anzeigebereichs"
#: src/ui/bigtext/bigtext.py:276 #: src/ui/bigtext/bigtext.py:288
msgid "Set Range End" msgid "Set Range End"
msgstr "Setze Ende des Anzeigebereichs" msgstr "Setze Ende des Anzeigebereichs"
#: src/ui/bigtext/bigtext.py:283 #: src/ui/bigtext/bigtext.py:295
msgid "Reset Range" msgid "Reset Range"
msgstr "Anzeigebereich Zurücksetzen" msgstr "Anzeigebereich Zurücksetzen"
#: src/ui/bigtext/bigtext.py:458 #: src/ui/bigtext/bigtext.py:526
msgid "warning" msgid "warning"
msgstr "Achtung" msgstr "Achtung"
#: src/ui/bigtext/bigtext.py:459 #: src/ui/bigtext/bigtext.py:527
msgid "You have selected <b>{0}</b> of data." msgid "You have selected <b>{0}</b> of data."
msgstr "Du hast <b>{0}</b> selektiert." msgstr "Du hast <b>{0}</b> selektiert."
#: src/ui/bigtext/bigtext.py:464 #: src/ui/bigtext/bigtext.py:532
msgid "Copy {0} to Clipboard" msgid "Copy {0} to Clipboard"
msgstr "Kopiere {0} in die Zwischenablage" msgstr "Kopiere {0} in die Zwischenablage"
#: src/ui/bigtext/bigtext.py:468 #: src/ui/bigtext/bigtext.py:536
msgid "Write to File" msgid "Write to File"
msgstr "Schreibe in Datei" msgstr "Schreibe in Datei"
#: src/ui/bigtext/bigtext.py:492 #: src/ui/bigtext/bigtext.py:560
msgid "Save File" msgid "Save File"
msgstr "Speichere Datei" msgstr "Speichere Datei"
#: src/ui/bigtext/bigtext.py:529 #: src/ui/bigtext/bigtext.py:605
msgid "selected {0} - {1:,.0f}:{2:,.0f}" msgid "selected {0} - {1:,.0f}:{2:,.0f}"
msgstr "selektiert {0} - {1:,.0f}:{2:,.0f}" msgstr "selektiert {0} - {1:,.0f}:{2:,.0f}"
@@ -306,6 +310,10 @@ msgstr "Zeilenhintergrund"
msgid "Regular Expression" msgid "Regular Expression"
msgstr "Regulärer Ausdruck" msgstr "Regulärer Ausdruck"
#: src/ui/bigtext/newhighlightingdialog.py:185
msgid "File Type:"
msgstr "Dateityp:"
#: src/ui/colorbutton.py:20 #: src/ui/colorbutton.py:20
msgid "Strawberry Cream" msgid "Strawberry Cream"
msgstr "Strawberry Cream" msgstr "Strawberry Cream"
@@ -370,7 +378,7 @@ msgstr "Grau"
msgid "transparent" msgid "transparent"
msgstr "Transparent" msgstr "Transparent"
#: src/ui/rangeslider.py:180 #: src/ui/rangeslider.py:190
msgid "showing bytes {0} to {1} ({2})" msgid "showing bytes {0} to {1} ({2})"
msgstr "Anzeigebereich: Bytes {0} bis {1} ({2})" msgstr "Anzeigebereich: Bytes {0} bis {1} ({2})"

View File

@@ -5,7 +5,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-03-24 12:00+0100\n" "POT-Creation-Date: 2025-03-24 19:02+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"
#: src/mainwindow.py:32 src/plugins/krowlog/aboutdialog.py:30 #: src/mainwindow.py:32 src/new_big_text/bigger_text.py:75
#: src/plugins/krowlogplugin.py:85 #: src/plugins/krowlog/aboutdialog.py:30 src/plugins/krowlogplugin.py:85
msgid "KrowLog" msgid "KrowLog"
msgstr "" msgstr ""
@@ -140,31 +140,31 @@ msgstr ""
msgid "E&xit" msgid "E&xit"
msgstr "" msgstr ""
#: src/plugins/logfile/filterwidget.py:181 #: src/plugins/logfile/filterwidget.py:192
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
#: src/plugins/logfile/filterwidget.py:187 #: src/plugins/logfile/filterwidget.py:198
msgid "save query" msgid "save query"
msgstr "" msgstr ""
#: src/plugins/logfile/filterwidget.py:192 #: src/plugins/logfile/filterwidget.py:203
msgid "ignore case" msgid "ignore case"
msgstr "" msgstr ""
#: src/plugins/logfile/filterwidget.py:196 #: src/plugins/logfile/filterwidget.py:207
msgid "regex" msgid "regex"
msgstr "" msgstr ""
#: src/plugins/logfile/filterwidget.py:206 #: src/plugins/logfile/filterwidget.py:217
msgid "only matches" msgid "only matches"
msgstr "" msgstr ""
#: src/plugins/logfile/filterwidget.py:298 #: src/plugins/logfile/filterwidget.py:309
msgid "({hits} lines)" msgid "({hits} lines)"
msgstr "" msgstr ""
#: src/plugins/logfileplugin.py:35 src/ui/bigtext/bigtext.py:258 #: src/plugins/logfileplugin.py:35 src/ui/bigtext/bigtext.py:263
msgid "&Highlighter" msgid "&Highlighter"
msgstr "" msgstr ""
@@ -208,51 +208,55 @@ msgstr ""
msgid "h" msgid "h"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:238 #: src/ui/bigtext/bigtext.py:243
msgid "&Copy to Clipboard" msgid "&Copy to Clipboard"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:246 #: src/ui/bigtext/bigtext.py:251
msgid "Copy to &File" msgid "Copy to &File"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:252 #: src/ui/bigtext/bigtext.py:257
msgid "Select &All" msgid "Select &All"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:268 #: src/ui/bigtext/bigtext.py:270
msgid "&Follow"
msgstr ""
#: src/ui/bigtext/bigtext.py:280
msgid "Set Range Start" msgid "Set Range Start"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:276 #: src/ui/bigtext/bigtext.py:288
msgid "Set Range End" msgid "Set Range End"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:283 #: src/ui/bigtext/bigtext.py:295
msgid "Reset Range" msgid "Reset Range"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:458 #: src/ui/bigtext/bigtext.py:526
msgid "warning" msgid "warning"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:459 #: src/ui/bigtext/bigtext.py:527
msgid "You have selected <b>{0}</b> of data." msgid "You have selected <b>{0}</b> of data."
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:464 #: src/ui/bigtext/bigtext.py:532
msgid "Copy {0} to Clipboard" msgid "Copy {0} to Clipboard"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:468 #: src/ui/bigtext/bigtext.py:536
msgid "Write to File" msgid "Write to File"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:492 #: src/ui/bigtext/bigtext.py:560
msgid "Save File" msgid "Save File"
msgstr "" msgstr ""
#: src/ui/bigtext/bigtext.py:529 #: src/ui/bigtext/bigtext.py:605
msgid "selected {0} - {1:,.0f}:{2:,.0f}" msgid "selected {0} - {1:,.0f}:{2:,.0f}"
msgstr "" msgstr ""
@@ -300,6 +304,10 @@ msgstr ""
msgid "Regular Expression" msgid "Regular Expression"
msgstr "" msgstr ""
#: src/ui/bigtext/newhighlightingdialog.py:185
msgid "File Type:"
msgstr ""
#: src/ui/colorbutton.py:20 #: src/ui/colorbutton.py:20
msgid "Strawberry Cream" msgid "Strawberry Cream"
msgstr "" msgstr ""
@@ -364,7 +372,7 @@ msgstr ""
msgid "transparent" msgid "transparent"
msgstr "" msgstr ""
#: src/ui/rangeslider.py:180 #: src/ui/rangeslider.py:190
msgid "showing bytes {0} to {1} ({2})" msgid "showing bytes {0} to {1} ({2})"
msgstr "" msgstr ""

View File

@@ -237,7 +237,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, source_model.get_file()) self.filter_model = LogFileModel(self.tmp_filename, self.source_model.settings, source_model.get_file())
self.hits_view = BigText(self.filter_model, show_range_slider=False) self.hits_view = BigText(self.filter_model, show_range_slider=False, show_follow_action=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

@@ -14,6 +14,9 @@ class BigScrollBar(QWidget):
code involved. We work around this by converting the python int code involved. We work around this by converting the python int
into a string.""" into a string."""
user_interaction = Signal()
"""signals that the user changed a value (the opposite is that some code changed the value) """
class ScrollEvent(enum.IntEnum): class ScrollEvent(enum.IntEnum):
PageUp = 1 PageUp = 1
PageDown = 2 PageDown = 2
@@ -138,21 +141,27 @@ class BigScrollBar(QWidget):
trigger_repeat_action = True trigger_repeat_action = True
match self.repeat_action_control: match self.repeat_action_control:
case QStyle.SubControl.SC_ScrollBarAddPage: case QStyle.SubControl.SC_ScrollBarAddPage:
self.user_interaction.emit()
self.scroll_event.emit(self.ScrollEvent.PageDown) self.scroll_event.emit(self.ScrollEvent.PageDown)
case QStyle.SubControl.SC_ScrollBarSubPage: case QStyle.SubControl.SC_ScrollBarSubPage:
self.user_interaction.emit()
self.scroll_event.emit(self.ScrollEvent.PageUp) self.scroll_event.emit(self.ScrollEvent.PageUp)
if self.value <= self.minimum: if self.value <= self.minimum:
trigger_repeat_action = False trigger_repeat_action = False
case QStyle.SubControl.SC_ScrollBarAddLine: case QStyle.SubControl.SC_ScrollBarAddLine:
self.user_interaction.emit()
self.scroll_event.emit(self.ScrollEvent.LinesDown) self.scroll_event.emit(self.ScrollEvent.LinesDown)
case QStyle.SubControl.SC_ScrollBarSubLine: case QStyle.SubControl.SC_ScrollBarSubLine:
self.user_interaction.emit()
self.scroll_event.emit(self.ScrollEvent.LinesUp) self.scroll_event.emit(self.ScrollEvent.LinesUp)
if self.value <= self.minimum: if self.value <= self.minimum:
trigger_repeat_action = False trigger_repeat_action = False
case QStyle.SubControl.SC_ScrollBarFirst: case QStyle.SubControl.SC_ScrollBarFirst:
self.user_interaction.emit()
self.set_value(self.minimum) self.set_value(self.minimum)
trigger_repeat_action = False trigger_repeat_action = False
case QStyle.SubControl.SC_ScrollBarLast: case QStyle.SubControl.SC_ScrollBarLast:
self.user_interaction.emit()
self.set_value(self.maximum) self.set_value(self.maximum)
trigger_repeat_action = False trigger_repeat_action = False
case _: case _:
@@ -180,6 +189,7 @@ class BigScrollBar(QWidget):
if not r.contains(event.position().toPoint()): if not r.contains(event.position().toPoint()):
new_position = self.snap_back_position new_position = self.snap_back_position
self.user_interaction.emit()
# print(f"move to value: {new_position}") # print(f"move to value: {new_position}")
self.set_value(new_position) self.set_value(new_position)
@@ -227,7 +237,10 @@ class BigScrollBar(QWidget):
self.repeat_action_timer.stop() self.repeat_action_timer.stop()
#self.update() #self.update()
def set_value(self, value: int): def set_value(self, value: int, emit_change_event=True):
changed = self.value != value
self.value = value self.value = value
self.value_changed.emit(str(self.value)) if emit_change_event and changed:
# print(f"emitting value changed: {self.value}")
self.value_changed.emit(str(self.value))
self.update() self.update()

View File

@@ -77,10 +77,11 @@ class FileWatchdogThread(QRunnable):
class BigText(QWidget): class BigText(QWidget):
trigger_update = Signal() trigger_update = Signal()
def __init__(self, model: LogFileModel, show_range_slider=True): def __init__(self, model: LogFileModel, show_range_slider=True, show_follow_action=True):
super(BigText, self).__init__() super(BigText, self).__init__()
self.show_range_slider = show_range_slider self.show_range_slider = show_range_slider
self.show_follow_action = show_follow_action
self.model = model self.model = model
self.grid = QGridLayout() self.grid = QGridLayout()
@@ -102,6 +103,7 @@ class BigText(QWidget):
# self.v_scroll_bar.setPageStep(1) # self.v_scroll_bar.setPageStep(1)
self.v_scroll_bar.value_changed.connect(self.big_text.v_scroll_value_changed) self.v_scroll_bar.value_changed.connect(self.big_text.v_scroll_value_changed)
self.v_scroll_bar.scroll_event.connect(self.big_text.v_scroll_event) self.v_scroll_bar.scroll_event.connect(self.big_text.v_scroll_event)
self.v_scroll_bar.user_interaction.connect(self.big_text.user_scroll_interaction)
if show_range_slider: if show_range_slider:
self.range_limit = RangeSlider() self.range_limit = RangeSlider()
@@ -154,6 +156,8 @@ class InnerBigText(QWidget):
_range_start = 0 _range_start = 0
_range_end = -1 _range_end = -1
_follow = False
def __init__(self, parent: BigText, model: LogFileModel, v_scaled_scrollbar: ScaledScrollBar): def __init__(self, parent: BigText, model: LogFileModel, v_scaled_scrollbar: ScaledScrollBar):
super(InnerBigText, self).__init__() super(InnerBigText, self).__init__()
self.char_height = None self.char_height = None
@@ -262,6 +266,12 @@ class InnerBigText(QWidget):
manage_highlighting.setShortcut("CTRL+H") manage_highlighting.setShortcut("CTRL+H")
menu.addAction(manage_highlighting) menu.addAction(manage_highlighting)
if self.parent.show_follow_action:
follow = QAction(_("&Follow"), self, triggered=self._toggle_follow)
follow.setCheckable(True)
follow.setChecked(self._follow)
menu.addAction(follow)
if self.parent.show_range_slider: if self.parent.show_range_slider:
menu.addSeparator() menu.addSeparator()
@@ -309,8 +319,12 @@ class InnerBigText(QWidget):
self.parent.range_limit.set_range_start(0) self.parent.range_limit.set_range_start(0)
self.parent.range_limit.set_range_end(self.model.byte_count()) self.parent.range_limit.set_range_end(self.model.byte_count())
def user_scroll_interaction(self):
self._follow = False
def scroll_by_lines(self, scroll_lines: int): def scroll_by_lines(self, scroll_lines: int):
self.scroll_lines = scroll_lines self.scroll_lines = scroll_lines
self._follow = False
self.update() self.update()
self.parent.v_scroll_bar.set_value(self._byte_offset) self.parent.v_scroll_bar.set_value(self._byte_offset)
@@ -565,6 +579,11 @@ class InnerBigText(QWidget):
self._update_highlight_selected_text() self._update_highlight_selected_text()
self.update() self.update()
def _toggle_follow(self):
self._follow = not self._follow
print(f"follow={self._follow}")
self.update()
def _update_highlight_selected_text(self): def _update_highlight_selected_text(self):
start_byte = self.selection_highlight.min_byte() start_byte = self.selection_highlight.min_byte()
end_byte = self.selection_highlight.max_byte() end_byte = self.selection_highlight.max_byte()
@@ -601,7 +620,7 @@ class InnerBigText(QWidget):
# "Noto Sans Mono" # "Noto Sans Mono"
# "Noto Color Emoji" # "Noto Color Emoji"
# "Andale Mono" # "Andale Mono"
qfont = QFont("Noto Sans Mono", self.model.settings.getint_session('general', "font_size")) qfont = QFont("Monospace", self.model.settings.getint_session('general', "font_size"))
qfont.setStyleHint(QFont.StyleHint.Monospace) qfont.setStyleHint(QFont.StyleHint.Monospace)
painter.setFont(qfont) painter.setFont(qfont)
self.font_metric = painter.fontMetrics() self.font_metric = painter.fontMetrics()
@@ -613,6 +632,11 @@ 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))
if self._range_end >= 0 and self._follow:
self.scroll_lines = 0
self._byte_offset = self.model.byte_count() - 1
self.parent.v_scroll_bar.set_value(self._byte_offset)
self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show, self._range_start, self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show, self._range_start,
self._range_end) 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)))

View File

@@ -1,4 +1,4 @@
01234 012345
01234567890123456789 01234567890123456789
012345678901234567890123456789012345678901234567890123456789 012345678901234567890123456789012345678901234567890123456789
tab indentation: tab indentation: