From 9902be0a482a3729eae969c3a25e19e3f5240e07 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 24 Mar 2025 19:20:49 +0100 Subject: [PATCH] feature: follow the file and show always the end when new data comes --- locales/de_DE/LC_MESSAGES/messages.mo | Bin 5063 -> 5268 bytes locales/de_DE/LC_MESSAGES/messages.po | 66 +++++++++++++++----------- locales/messages.pot | 54 ++++++++++++--------- src/plugins/logfile/filterwidget.py | 2 +- src/ui/bigtext/BigScrollBar.py | 17 ++++++- src/ui/bigtext/bigtext.py | 28 ++++++++++- testbed/example.log | 2 +- 7 files changed, 111 insertions(+), 58 deletions(-) diff --git a/locales/de_DE/LC_MESSAGES/messages.mo b/locales/de_DE/LC_MESSAGES/messages.mo index f7514afe2ef63c6f913e6c8d1183294b72b527f2..fb2b43379c3c126ebd0be55b49d084007e52c029 100644 GIT binary patch delta 2158 zcmXxlTWnNC9LMqh_Cjg9ZD~uX1;m9S%c8wOOKB@qfnq5lwiJ-|fi(4Wi|KaDwpkq9pc<8UHEJT8PzkoW_HNWbdr%1{u@sM@`k%xiJcs!> zjmq;a*5i+;{+SG#tEHYzMGq`M-B^Mg*2qZ-*P;@3qVD%OWA6G}s0k!66F)}AuuoA- z{sk(}SMK^x_yq0i7}o=LsVISu>FOJop_Xtd>J4f*DPfCix1m<36E(42sEI{U1HFmk z_&zFsE+_S$gKRGgpsrW?S$`#}rS&wfK_9+`^tA!kj-fh^A&2efq;Gf__52j_4)zWP z@IzdH7g2exp;q`NYP`R&mX81WS%1xV87FPBCe%!~A^XL4p;lrL)iH`n^oF~C#NB@n zwGzir{m;1jpP?pj5jpH@cl{S!N&ELW6%AZUZzZVVq=8zUn^6gRQJ*M`8sHG>QysyD z_z`NN)2NAGLiM|hdj40OjejC9Z}(6y63^hnX{qv17ec6k>QKA84YgT1Py_b6`} zPoesq$2Isl7ULb%K-n}ju@YoVt3XXGgyf4`0~HQye|*7ukiHf{E!hNW0`H=B_gPee zbEuX367}5Ar~z+aEB@`;)r_JSYH@Bstw=x4*Y7_neD~M&pi)v8f<($?Muc$>?Oem?AIzW&s zRaSG}Oz2HiULvZ9UgBBe8Db|icUco867)QJX{GU8RdynyRtf zsExRZSVi;@6+{zJPjnLc>7{Fa&_Ai-L@1|Y#)jz7P;`HCPfocnyL)`ZYfetiY|IP}+V1dh zH0A~R`$j#BSY*_q!$aeNNZ(lhpf_qUFYFz#(Zsd<(*+GxwJWNY*9YpFn(G=9hyDNf z8WQ^owkvhm8%|y>*x}0>8y{&-&MW#a(>Iv-rl_(am2r4)EYKbE1_r#Cb$Q{o10!VI HSUT|t-l@9T delta 1949 zcmYk+Uu+ab9Ki7@t+o{IinLXbe@Cmdprv=$Y6~h_5rkGzkv3|g3281!Es(Ynib_r+ z-~*Zv*MIS)7y^L@9;BuTB$|+5iQ$c?kU)4qG#DQwMtw5q_j{QpPWE@7+1Z`n%+BoX zM@!E&6|c^&_&88{iTT9YX(0^Z;BEX+vXvp+jyar-omhoE(M{;BFJl_}ks}Pp_BU`Q z=Wk;*et_ot49QarV^pToa11%ZNq(B}G|t0oXyRMwKq-2quoi7!jI%I{Chm&Y*I_;9 zeOQ5mX#XLcfx9rx_~BhDCj1Z?BOF3I9*gJSpaV>zi7sL-UO^{t6Kn8aG;s}2W1e}~ zj*V#l7my=t<;UwIwljWslZs38KAP}TG~rQiz=`O&*nSC}zzr*xTlki`D4 zA+J-|iMEfTdG_JGn9N}PsfSbXhHue5x`5;gmoS4r;X=o4N>JN|}V{|g=X7CJyRKeo@s2eAPi z@I|!$PUP0GFPfnJzd)D%1e*U$k&0Vz9v92=+ z`6tK`j`PE_gwyB*zC&NuYiR#pkQFP2Kd5+Pnk){u03XF=@q7S%qFvDg=+cd$AFSi( z#3s=R{fMr}ueb=SXk>`cj5LK6IDkD^uAEi(Iu;AHs0TX zuFPt50^QhvFJTkzLGL?)uJD)WJ8=qmSHok(8pbbO>_*y49Zb53@Wrw`PTWs0e#jE* z2v_X?<;i%`ff>Rl-bgeOuI4j@#ebKdddm}phd|1$> z_bKlrd{HgFKU2lMwme1n4e-e=cN6Q0)dXM1Vt9ax`{_%vgm8)dI6O@F8J;R`O&j6A zU?p)6VexObg2)l~5pKZ(qKk0*HW1Gej}Uocsytt+uwKijTCg+L-EWKg+C#Jut;Aa5 zX<}}2rm}mywyM5tylr}}eBstD+jk5XGX0xJ3Sr0g!QGi{n_usLwJ;Kf3tI}K$$^=N zQtd6-ww8Q*CYN8C%_p6y-^;Vhb4hc$Z+w5cw`~09nm@~v%e4*3w7R-vPTgDo0cfYA AX#fBK diff --git a/locales/de_DE/LC_MESSAGES/messages.po b/locales/de_DE/LC_MESSAGES/messages.po index 99b49d1..cbccf67 100644 --- a/locales/de_DE/LC_MESSAGES/messages.po +++ b/locales/de_DE/LC_MESSAGES/messages.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: RavenLog\n" -"POT-Creation-Date: 2024-03-24 12:00+0100\n" -"PO-Revision-Date: 2024-03-24 12:02+0100\n" +"POT-Creation-Date: 2025-03-24 19:02+0100\n" +"PO-Revision-Date: 2025-03-24 19:17+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: de\n" @@ -15,10 +15,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\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/plugins/krowlogplugin.py:85 +#: src/mainwindow.py:32 src/new_big_text/bigger_text.py:75 +#: src/plugins/krowlog/aboutdialog.py:30 src/plugins/krowlogplugin.py:85 msgid "KrowLog" msgstr "KrowLog" @@ -146,31 +146,31 @@ msgstr "&Über KrowLog" msgid "E&xit" msgstr "&Beenden" -#: src/plugins/logfile/filterwidget.py:181 +#: src/plugins/logfile/filterwidget.py:192 msgid "Cancel" msgstr "Abbrechen" -#: src/plugins/logfile/filterwidget.py:187 +#: src/plugins/logfile/filterwidget.py:198 msgid "save query" msgstr "suche speichern" -#: src/plugins/logfile/filterwidget.py:192 +#: src/plugins/logfile/filterwidget.py:203 msgid "ignore case" msgstr "Groß-/Kleinschreibung ignorieren" -#: src/plugins/logfile/filterwidget.py:196 +#: src/plugins/logfile/filterwidget.py:207 msgid "regex" msgstr "RegExp" -#: src/plugins/logfile/filterwidget.py:206 +#: src/plugins/logfile/filterwidget.py:217 msgid "only matches" msgstr "nur Treffer" -#: src/plugins/logfile/filterwidget.py:298 +#: src/plugins/logfile/filterwidget.py:309 msgid "({hits} lines)" 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" msgstr "&Hervorhebungen" @@ -200,65 +200,69 @@ msgstr "Öffne Datei" #: src/plugins/timediff/time_diff_menu_widget.py:32 msgid "ms" -msgstr "" +msgstr "ms" #: src/plugins/timediff/time_diff_menu_widget.py:33 msgid "s" -msgstr "" +msgstr "s" #: src/plugins/timediff/time_diff_menu_widget.py:34 msgid "m" -msgstr "" +msgstr "m" #: src/plugins/timediff/time_diff_menu_widget.py:35 msgid "h" -msgstr "" +msgstr "h" -#: src/ui/bigtext/bigtext.py:238 +#: src/ui/bigtext/bigtext.py:243 msgid "&Copy to Clipboard" msgstr "In Zwischenablage &Kopieren" -#: src/ui/bigtext/bigtext.py:246 +#: src/ui/bigtext/bigtext.py:251 msgid "Copy to &File" msgstr "In &Datei Kopieren" -#: src/ui/bigtext/bigtext.py:252 +#: src/ui/bigtext/bigtext.py:257 msgid "Select &All" 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" msgstr "Setze Start des Anzeigebereichs" -#: src/ui/bigtext/bigtext.py:276 +#: src/ui/bigtext/bigtext.py:288 msgid "Set Range End" msgstr "Setze Ende des Anzeigebereichs" -#: src/ui/bigtext/bigtext.py:283 +#: src/ui/bigtext/bigtext.py:295 msgid "Reset Range" msgstr "Anzeigebereich Zurücksetzen" -#: src/ui/bigtext/bigtext.py:458 +#: src/ui/bigtext/bigtext.py:526 msgid "warning" msgstr "Achtung" -#: src/ui/bigtext/bigtext.py:459 +#: src/ui/bigtext/bigtext.py:527 msgid "You have selected {0} of data." msgstr "Du hast {0} selektiert." -#: src/ui/bigtext/bigtext.py:464 +#: src/ui/bigtext/bigtext.py:532 msgid "Copy {0} to Clipboard" msgstr "Kopiere {0} in die Zwischenablage" -#: src/ui/bigtext/bigtext.py:468 +#: src/ui/bigtext/bigtext.py:536 msgid "Write to File" msgstr "Schreibe in Datei" -#: src/ui/bigtext/bigtext.py:492 +#: src/ui/bigtext/bigtext.py:560 msgid "Save File" msgstr "Speichere Datei" -#: src/ui/bigtext/bigtext.py:529 +#: src/ui/bigtext/bigtext.py:605 msgid "selected {0} - {1:,.0f}:{2:,.0f}" msgstr "selektiert {0} - {1:,.0f}:{2:,.0f}" @@ -306,6 +310,10 @@ msgstr "Zeilenhintergrund" msgid "Regular Expression" msgstr "Regulärer Ausdruck" +#: src/ui/bigtext/newhighlightingdialog.py:185 +msgid "File Type:" +msgstr "Dateityp:" + #: src/ui/colorbutton.py:20 msgid "Strawberry Cream" msgstr "Strawberry Cream" @@ -370,7 +378,7 @@ msgstr "Grau" msgid "transparent" msgstr "Transparent" -#: src/ui/rangeslider.py:180 +#: src/ui/rangeslider.py:190 msgid "showing bytes {0} to {1} ({2})" msgstr "Anzeigebereich: Bytes {0} bis {1} ({2})" diff --git a/locales/messages.pot b/locales/messages.pot index 3309562..86f4fdf 100644 --- a/locales/messages.pot +++ b/locales/messages.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "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" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,8 +15,8 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: src/mainwindow.py:32 src/plugins/krowlog/aboutdialog.py:30 -#: src/plugins/krowlogplugin.py:85 +#: src/mainwindow.py:32 src/new_big_text/bigger_text.py:75 +#: src/plugins/krowlog/aboutdialog.py:30 src/plugins/krowlogplugin.py:85 msgid "KrowLog" msgstr "" @@ -140,31 +140,31 @@ msgstr "" msgid "E&xit" msgstr "" -#: src/plugins/logfile/filterwidget.py:181 +#: src/plugins/logfile/filterwidget.py:192 msgid "Cancel" msgstr "" -#: src/plugins/logfile/filterwidget.py:187 +#: src/plugins/logfile/filterwidget.py:198 msgid "save query" msgstr "" -#: src/plugins/logfile/filterwidget.py:192 +#: src/plugins/logfile/filterwidget.py:203 msgid "ignore case" msgstr "" -#: src/plugins/logfile/filterwidget.py:196 +#: src/plugins/logfile/filterwidget.py:207 msgid "regex" msgstr "" -#: src/plugins/logfile/filterwidget.py:206 +#: src/plugins/logfile/filterwidget.py:217 msgid "only matches" msgstr "" -#: src/plugins/logfile/filterwidget.py:298 +#: src/plugins/logfile/filterwidget.py:309 msgid "({hits} lines)" 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" msgstr "" @@ -208,51 +208,55 @@ msgstr "" msgid "h" msgstr "" -#: src/ui/bigtext/bigtext.py:238 +#: src/ui/bigtext/bigtext.py:243 msgid "&Copy to Clipboard" msgstr "" -#: src/ui/bigtext/bigtext.py:246 +#: src/ui/bigtext/bigtext.py:251 msgid "Copy to &File" msgstr "" -#: src/ui/bigtext/bigtext.py:252 +#: src/ui/bigtext/bigtext.py:257 msgid "Select &All" 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" msgstr "" -#: src/ui/bigtext/bigtext.py:276 +#: src/ui/bigtext/bigtext.py:288 msgid "Set Range End" msgstr "" -#: src/ui/bigtext/bigtext.py:283 +#: src/ui/bigtext/bigtext.py:295 msgid "Reset Range" msgstr "" -#: src/ui/bigtext/bigtext.py:458 +#: src/ui/bigtext/bigtext.py:526 msgid "warning" msgstr "" -#: src/ui/bigtext/bigtext.py:459 +#: src/ui/bigtext/bigtext.py:527 msgid "You have selected {0} of data." msgstr "" -#: src/ui/bigtext/bigtext.py:464 +#: src/ui/bigtext/bigtext.py:532 msgid "Copy {0} to Clipboard" msgstr "" -#: src/ui/bigtext/bigtext.py:468 +#: src/ui/bigtext/bigtext.py:536 msgid "Write to File" msgstr "" -#: src/ui/bigtext/bigtext.py:492 +#: src/ui/bigtext/bigtext.py:560 msgid "Save File" msgstr "" -#: src/ui/bigtext/bigtext.py:529 +#: src/ui/bigtext/bigtext.py:605 msgid "selected {0} - {1:,.0f}:{2:,.0f}" msgstr "" @@ -300,6 +304,10 @@ msgstr "" msgid "Regular Expression" msgstr "" +#: src/ui/bigtext/newhighlightingdialog.py:185 +msgid "File Type:" +msgstr "" + #: src/ui/colorbutton.py:20 msgid "Strawberry Cream" msgstr "" @@ -364,7 +372,7 @@ msgstr "" msgid "transparent" msgstr "" -#: src/ui/rangeslider.py:180 +#: src/ui/rangeslider.py:190 msgid "showing bytes {0} to {1} ({2})" msgstr "" diff --git a/src/plugins/logfile/filterwidget.py b/src/plugins/logfile/filterwidget.py index 59e5292..ff3512c 100644 --- a/src/plugins/logfile/filterwidget.py +++ b/src/plugins/logfile/filterwidget.py @@ -237,7 +237,7 @@ class FilterWidget(QWidget): (handle, self.tmp_filename) = tempfile.mkstemp() os.close(handle) 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(self.hits_view) diff --git a/src/ui/bigtext/BigScrollBar.py b/src/ui/bigtext/BigScrollBar.py index 8504bff..66a48fb 100644 --- a/src/ui/bigtext/BigScrollBar.py +++ b/src/ui/bigtext/BigScrollBar.py @@ -14,6 +14,9 @@ class BigScrollBar(QWidget): code involved. We work around this by converting the python int 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): PageUp = 1 PageDown = 2 @@ -138,21 +141,27 @@ class BigScrollBar(QWidget): trigger_repeat_action = True match self.repeat_action_control: case QStyle.SubControl.SC_ScrollBarAddPage: + self.user_interaction.emit() self.scroll_event.emit(self.ScrollEvent.PageDown) case QStyle.SubControl.SC_ScrollBarSubPage: + self.user_interaction.emit() self.scroll_event.emit(self.ScrollEvent.PageUp) if self.value <= self.minimum: trigger_repeat_action = False case QStyle.SubControl.SC_ScrollBarAddLine: + self.user_interaction.emit() self.scroll_event.emit(self.ScrollEvent.LinesDown) case QStyle.SubControl.SC_ScrollBarSubLine: + self.user_interaction.emit() self.scroll_event.emit(self.ScrollEvent.LinesUp) if self.value <= self.minimum: trigger_repeat_action = False case QStyle.SubControl.SC_ScrollBarFirst: + self.user_interaction.emit() self.set_value(self.minimum) trigger_repeat_action = False case QStyle.SubControl.SC_ScrollBarLast: + self.user_interaction.emit() self.set_value(self.maximum) trigger_repeat_action = False case _: @@ -180,6 +189,7 @@ class BigScrollBar(QWidget): if not r.contains(event.position().toPoint()): new_position = self.snap_back_position + self.user_interaction.emit() # print(f"move to value: {new_position}") self.set_value(new_position) @@ -227,7 +237,10 @@ class BigScrollBar(QWidget): self.repeat_action_timer.stop() #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_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() diff --git a/src/ui/bigtext/bigtext.py b/src/ui/bigtext/bigtext.py index 88a2ec5..3b87980 100644 --- a/src/ui/bigtext/bigtext.py +++ b/src/ui/bigtext/bigtext.py @@ -77,10 +77,11 @@ class FileWatchdogThread(QRunnable): class BigText(QWidget): 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__() self.show_range_slider = show_range_slider + self.show_follow_action = show_follow_action self.model = model self.grid = QGridLayout() @@ -102,6 +103,7 @@ class BigText(QWidget): # self.v_scroll_bar.setPageStep(1) 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.user_interaction.connect(self.big_text.user_scroll_interaction) if show_range_slider: self.range_limit = RangeSlider() @@ -154,6 +156,8 @@ class InnerBigText(QWidget): _range_start = 0 _range_end = -1 + _follow = False + def __init__(self, parent: BigText, model: LogFileModel, v_scaled_scrollbar: ScaledScrollBar): super(InnerBigText, self).__init__() self.char_height = None @@ -262,6 +266,12 @@ class InnerBigText(QWidget): manage_highlighting.setShortcut("CTRL+H") 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: menu.addSeparator() @@ -309,8 +319,12 @@ class InnerBigText(QWidget): self.parent.range_limit.set_range_start(0) 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): self.scroll_lines = scroll_lines + self._follow = False self.update() self.parent.v_scroll_bar.set_value(self._byte_offset) @@ -565,6 +579,11 @@ class InnerBigText(QWidget): self._update_highlight_selected_text() self.update() + def _toggle_follow(self): + self._follow = not self._follow + print(f"follow={self._follow}") + self.update() + def _update_highlight_selected_text(self): start_byte = self.selection_highlight.min_byte() end_byte = self.selection_highlight.max_byte() @@ -601,7 +620,7 @@ class InnerBigText(QWidget): # "Noto Sans Mono" # "Noto Color Emoji" # "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) painter.setFont(qfont) self.font_metric = painter.fontMetrics() @@ -613,6 +632,11 @@ class InnerBigText(QWidget): lines_to_show = math.ceil(self.lines_shown()) # 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._range_end) # print("lines_to_show: %d returned: %d" % (lines_to_show, len(self.lines))) diff --git a/testbed/example.log b/testbed/example.log index 59e0196..12ac9e3 100644 --- a/testbed/example.log +++ b/testbed/example.log @@ -1,4 +1,4 @@ -01234 +012345 01234567890123456789 012345678901234567890123456789012345678901234567890123456789 tab indentation: