From f3a68d0dee8ba47e5dd2ae5eac30e4be7b4bd456 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 24 Mar 2024 12:06:48 +0100 Subject: [PATCH] add context menu actions to set range start and end --- locales/de_DE/LC_MESSAGES/messages.mo | Bin 4775 -> 5063 bytes locales/de_DE/LC_MESSAGES/messages.po | 34 ++++++++---- locales/messages.pot | 30 ++++++++--- src/ui/bigtext/bigtext.py | 71 +++++++++++++++++++++----- src/ui/rangeslider.py | 54 +++++++++++++++++--- 5 files changed, 155 insertions(+), 34 deletions(-) diff --git a/locales/de_DE/LC_MESSAGES/messages.mo b/locales/de_DE/LC_MESSAGES/messages.mo index 273881b7be37553b8982164236545b4c76cf49d0..f7514afe2ef63c6f913e6c8d1183294b72b527f2 100644 GIT binary patch delta 2145 zcmZvcO>9(E6vt0Xr7*QEZAIn#L7~$k+L;k8Q~{^hN-3hYP!*%ev^>j{vDlfZg*KDX zSTIIS2n|Ts6k`{*zk*i8t^6e)sd7bI-l+ zeYNCVFngu4XunZ5qq*p8p;|&rfYV@`<0h!7Z^AOz4S6i-`iJ0y zwBLsT_!*SFgAhAe8>2Fvj$@F=PVoxDGjI;P3T5~Xl%rBsmBK2h{)KP`3_%%=y76^z zChbmG1QSr}`(X(jgk|`*52?uDK8O!H47Ko>YkvpjU;@g}MOX!Yg9_j_EQkL>87^lx zvNH!Rht*K)UxPdr=cVzK`tfhWRFs-ep$vWwW$>sbz;VZOuKyBL05{+i_z&dC8&RqQ z7?Yhxp!#dzqc8+D-U_w86J~X$y;PLC4Ac%rpcd|R?L$x*Itmro*HD3-g>v)@+y$>g zId}^rTE87~oooQAeBSpyc_r#YKNDh7T$sy{|n0T9ViC@ zUh1C(pN5N|9KH^>l`V&z0zt2+95uAq$;T5O|Wkn8(p%%`755c*R zOW6h4DzFKtfPRI_$W6EaPNNeSRtxE}m9Q7K!E$~7<5U#U1XRi{Km~FU zYQc3VgMUM%Y$nlYegjly);?ZySKdH8V%4x+HpIoM#|<(NJU?le)THPBl*vl1&-SJE9e=d zPjD$xsYA8-8b21O)N7XyBVAM#-Ji*#vsT%F^bgR^Rc51Bv=;Gq%-T~_be_5-HApGe z&*535-|%G7(L9Ot6*Qv7NJXFBN)$$qAsxXy6h%6|jp${x3PsRl>Bv{u<`a`WaD}Vu zyj66rZRl}Sk6O@+Xcn^E?^9o$vZmcn`Dw2`*4N`(N9;Y{Yl$bQ`3b)}?bSpR3F>a# zYwp{6PpcyxOQv(JfoQ?})V3Xi@xC6fYggJ&dBdTMm)_wGhcjO7a3oVV`fkhCujy{cU2#Ic8}mqI^?%Ed=>h-% delta 1827 zcmZ9MSxA*Z6vvOdsn<*`(==Q&ms@JKxaY03w9*z#Dtf34GTKCoo~}XBLPT{b>LntQ zAflrCRL}xZB0&&Q4;5ulU?GKXWgz|jIzcqde||Ib%{gbjGxL4@`PcLO9}>gQ8)Xej zN7q8lcEjQb8p>d#8Pz_~B*GyW4Szd^N117<2gbuBNVRM?UkKwEm%tcU1Lbcy#E;)v z=uBdw9a3#8O+M^|GvGNW$G4yYJ%Aqg#Ld5i35*A!9FMr?KjBoykwgiH=}`7rFc#*+ zc;eeUI&$cP*jOu+VY?gefeLT{%F!{H1W!S2>>;#(0NrKTFnVI!2oHZ6cV91ptr<4_y82*cn_NVPjOO7(pxKmBh04V=z+&^`YJ zWgkgUzs@v`j#B4^JhO7BH>ri%KogY1P4E!xgbMT-YW)c0+SqS5KL(Z2Se)d+R49LS zG_q@kI*RsK^3Ph^!bB$A38{9HMk%@g<>)dj3*k+nHu4cKx*Ol2HW0%ivTVsvFOmUe zm+R)s+Pyru9Id~7LHtaYGWgm^PGL{S# zAP*|Tb72c3RIx_5r$*>nHMdzV1a23vkH{5st>g--ZUB)j^XZsB*P#C+@ z^J!243!(h1gtc%zoB{(-ar}LBw4=L_YWHZgp#dm|ub~Wv+;|k~4Lvl(w3$#F@Iqb2 z1}OU`sEoBit?Pmcco^2f(-ULAy`ZBVzjOQnmAWvZ63aYL8_9q?vJyzOdYVqS4r<*) zsK76vGV>NH;73TcVH#y}3@S4jIMw~LIy%ZgGnAvXFdJ?iUto3=DurjE&ioSOE{-49 zG&md0L%QiIi%>mEMLx6|%|&{tLR5yd(H0c0?|&gu3U$${Q8Uu#@o&)vE6^&WPptqg zM*3yfp#O_fud)WmKAh3s_`SyTvlKtBFS4xPq#&-Xabf7 z^~26UIyhag5>y=YMr{ZSoQX*ZK8>jh3FO3Wj4I76t*9(72_A_n2u<*H?cLR}C)3x{ d-QCf(t!H2Gas1cNz_Tg2!Ggr~A%VW6>_1RBjf?;Q diff --git a/locales/de_DE/LC_MESSAGES/messages.po b/locales/de_DE/LC_MESSAGES/messages.po index ce677f1..99b49d1 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-21 19:39+0100\n" -"PO-Revision-Date: 2024-03-21 19:40+0100\n" +"POT-Creation-Date: 2024-03-24 12:00+0100\n" +"PO-Revision-Date: 2024-03-24 12:02+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: de\n" @@ -226,27 +226,39 @@ msgstr "In &Datei Kopieren" msgid "Select &All" msgstr "&Alles Selektieren" -#: src/ui/bigtext/bigtext.py:414 +#: src/ui/bigtext/bigtext.py:268 +msgid "Set Range Start" +msgstr "Setze Start des Anzeigebereichs" + +#: src/ui/bigtext/bigtext.py:276 +msgid "Set Range End" +msgstr "Setze Ende des Anzeigebereichs" + +#: src/ui/bigtext/bigtext.py:283 +msgid "Reset Range" +msgstr "Anzeigebereich Zurücksetzen" + +#: src/ui/bigtext/bigtext.py:458 msgid "warning" msgstr "Achtung" -#: src/ui/bigtext/bigtext.py:415 +#: src/ui/bigtext/bigtext.py:459 msgid "You have selected {0} of data." msgstr "Du hast {0} selektiert." -#: src/ui/bigtext/bigtext.py:420 +#: src/ui/bigtext/bigtext.py:464 msgid "Copy {0} to Clipboard" msgstr "Kopiere {0} in die Zwischenablage" -#: src/ui/bigtext/bigtext.py:424 +#: src/ui/bigtext/bigtext.py:468 msgid "Write to File" msgstr "Schreibe in Datei" -#: src/ui/bigtext/bigtext.py:448 +#: src/ui/bigtext/bigtext.py:492 msgid "Save File" msgstr "Speichere Datei" -#: src/ui/bigtext/bigtext.py:485 +#: src/ui/bigtext/bigtext.py:529 msgid "selected {0} - {1:,.0f}:{2:,.0f}" msgstr "selektiert {0} - {1:,.0f}:{2:,.0f}" @@ -304,7 +316,7 @@ msgstr "Pale Crimson" #: src/ui/colorbutton.py:23 msgid "Broken Buttercup" -msgstr "Broken Buttercup" +msgstr "Kaputtes Butterfass" #: src/ui/colorbutton.py:24 msgid "Passion Fruit Sugar" @@ -358,6 +370,10 @@ msgstr "Grau" msgid "transparent" msgstr "Transparent" +#: src/ui/rangeslider.py:180 +msgid "showing bytes {0} to {1} ({2})" +msgstr "Anzeigebereich: Bytes {0} bis {1} ({2})" + #~ msgid "data selection" #~ msgstr "selektion" diff --git a/locales/messages.pot b/locales/messages.pot index e384aa3..3309562 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-21 19:39+0100\n" +"POT-Creation-Date: 2024-03-24 12:00+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -220,27 +220,39 @@ msgstr "" msgid "Select &All" msgstr "" -#: src/ui/bigtext/bigtext.py:414 +#: src/ui/bigtext/bigtext.py:268 +msgid "Set Range Start" +msgstr "" + +#: src/ui/bigtext/bigtext.py:276 +msgid "Set Range End" +msgstr "" + +#: src/ui/bigtext/bigtext.py:283 +msgid "Reset Range" +msgstr "" + +#: src/ui/bigtext/bigtext.py:458 msgid "warning" msgstr "" -#: src/ui/bigtext/bigtext.py:415 +#: src/ui/bigtext/bigtext.py:459 msgid "You have selected {0} of data." msgstr "" -#: src/ui/bigtext/bigtext.py:420 +#: src/ui/bigtext/bigtext.py:464 msgid "Copy {0} to Clipboard" msgstr "" -#: src/ui/bigtext/bigtext.py:424 +#: src/ui/bigtext/bigtext.py:468 msgid "Write to File" msgstr "" -#: src/ui/bigtext/bigtext.py:448 +#: src/ui/bigtext/bigtext.py:492 msgid "Save File" msgstr "" -#: src/ui/bigtext/bigtext.py:485 +#: src/ui/bigtext/bigtext.py:529 msgid "selected {0} - {1:,.0f}:{2:,.0f}" msgstr "" @@ -352,3 +364,7 @@ msgstr "" msgid "transparent" msgstr "" +#: src/ui/rangeslider.py:180 +msgid "showing bytes {0} to {1} ({2})" +msgstr "" + diff --git a/src/ui/bigtext/bigtext.py b/src/ui/bigtext/bigtext.py index 37aaaa8..a6e6eb7 100644 --- a/src/ui/bigtext/bigtext.py +++ b/src/ui/bigtext/bigtext.py @@ -87,7 +87,10 @@ class BigText(QWidget): self.v_scroll_bar = ScaledScrollBar() - self.big_text = InnerBigText(self, model, self.v_scroll_bar) + self.range_limit = RangeSlider() + self.range_limit.value_changed.connect(self._range_limit_event) + + self.big_text = InnerBigText(self, model, self.v_scroll_bar, self.range_limit) self.big_text.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)) self.h_scroll_bar = QScrollBar(Qt.Orientation.Horizontal) @@ -99,8 +102,7 @@ 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.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) @@ -112,12 +114,9 @@ class BigText(QWidget): 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} -- range limit event") - self.big_text.set_range(range_start, range_end) + def _range_limit_event(self, range_start: str, range_end: str): + # print("-> %s, %s -- range limit event" %(range_start, range_end)) + self.big_text.set_range(int(range_start), int(range_end)) def get_file(self): return self.model.get_file() @@ -150,12 +149,14 @@ class InnerBigText(QWidget): _range_start = 0 _range_end = -1 - def __init__(self, parent: BigText, model: LogFileModel, v_scaled_scrollbar: ScaledScrollBar): + def __init__(self, parent: BigText, model: LogFileModel, v_scaled_scrollbar: ScaledScrollBar, + range_limit: RangeSlider): super(InnerBigText, self).__init__() self.char_height = None self.char_width = None self.model = model self._v_scaled_scrollbar = v_scaled_scrollbar + self._range_limit = range_limit self.parent = parent self.setFocusPolicy(Qt.FocusPolicy.StrongFocus) self.setFocusPolicy(Qt.FocusPolicy.WheelFocus) @@ -232,7 +233,7 @@ class InnerBigText(QWidget): # print("wheel event fired :) %s" % (direction)) self.scroll_by_lines(direction * 3) - def _open_menu(self, position): + def _open_menu(self, position: QPoint): menu = QMenu(self) copy_clipboard = QAction(Icon.fromTheme("edit-copy", "icons/myicons/edit-copy.svg"), _("&Copy to Clipboard"), @@ -261,8 +262,52 @@ class InnerBigText(QWidget): manage_highlighting.setShortcut("CTRL+H") menu.addAction(manage_highlighting) + menu.addSeparator() + + set_range_start = QAction( + Icon("icons/myicons/range-start.svg"), + _("Set Range Start"), + self, + triggered=lambda: self._set_range_start_by_y_pos(position.y()) + ) + menu.addAction(set_range_start) + + set_range_end = QAction( + Icon("icons/myicons/range-end.svg"), + _("Set Range End"), + self, + triggered=lambda: self._set_range_end_by_y_pos(position.y()) + ) + menu.addAction(set_range_end) + + reset_range = QAction( + _("Reset Range"), + self, + triggered=lambda: self._reset_range() + ) + menu.addAction(reset_range) + menu.exec(self.mapToGlobal(position)) + def _set_range_start_by_y_pos(self, y_pos: int) -> None: + line_number = self.y_pos_to_line(y_pos) + self.lines = self.model.data(self._byte_offset, 0, line_number + 1, self._range_start, + self._range_end) + range_start = self.lines[line_number].byte_offset() + self.parent.range_limit.set_range_start(range_start) + + def _set_range_end_by_y_pos(self, y_pos: int) -> None: + line_number = self.y_pos_to_line(y_pos) + self.lines = self.model.data(self._byte_offset, 0, line_number + 1, self._range_start, + self._range_end) + range_end = self.lines[line_number].byte_end() + 1 + + self.parent.range_limit.set_range_end(range_end) + + def _reset_range(self): + self.parent.range_limit.set_range_start(0) + self.parent.range_limit.set_range_end(self.model.byte_count()) + def scroll_by_lines(self, scroll_lines: int): self.scroll_lines = scroll_lines self.update() @@ -511,8 +556,10 @@ class InnerBigText(QWidget): self._byte_offset = self.lines[0].byte_offset() if len(self.lines) > 0 else 0 # print("new byte offset: ", self._byte_offset) # document length == maximum + pageStep + aFewBytesSoThatTheLastLineIsShown - vmax = self.model.byte_count() - 1 if self._range_end < 0 else min(self._range_end, self.model.byte_count() - 1) + byte_count = self.model.byte_count() + vmax = byte_count - 1 if self._range_end < 0 else min(self._range_end, self.model.byte_count() - 1) self.parent.v_scroll_bar.setMaximum(vmax) + self.parent.range_limit.set_maximum(byte_count) for line in self.lines: self.update_longest_line(len(line.line())) diff --git a/src/ui/rangeslider.py b/src/ui/rangeslider.py index 408ce75..c73756a 100644 --- a/src/ui/rangeslider.py +++ b/src/ui/rangeslider.py @@ -7,8 +7,10 @@ from PySide6.QtCore import QRect, QPoint, Signal from PySide6.QtGui import QPainter, Qt from PySide6.QtWidgets import QWidget +from src.pluginregistry import PluginRegistry +from src.util import conversion from src.util.color import to_qcolor - +from src.i18n import _ class RangeSliderHandle(): def __init__(self, value: int): @@ -27,7 +29,13 @@ class UpdateStyle(Enum): class RangeSlider(QWidget): - value_changed = Signal(float, float) + value_changed = Signal(str, str) + """Signal emitted when the range slider value changes. + **Note**: The value is a string and must be parsed into an int. + QT's signal api only supports 32bit integers. Ints larger + than 2**32-1 will overflow. Probably because there is some C/C++ + code involved. We work around this by converting the python int + into a string.""" _width = 20 _handle_width = 12 @@ -42,11 +50,22 @@ class RangeSlider(QWidget): self.max_value = 100 self.lower_value = RangeSliderHandle(0) - self.upper_value = RangeSliderHandle(100) + self.upper_value = RangeSliderHandle(self.max_value) self.selected_handle = None self.selection_drag_range = (self.min_value, self.max_value) + def set_maximum(self, max: int): + if self.max_value == max: + return + was_at_max = self.upper_value.value == self.max_value + + self.max_value = max + + if was_at_max: + self.upper_value.value = max + self._emit_value_changed() + def paintEvent(self, event: PySide6.QtGui.QPaintEvent) -> None: painter = QPainter(self) self._draw_background(painter) @@ -104,13 +123,13 @@ class RangeSlider(QWidget): painter.drawEllipse(QPoint(self._width / 2, y_pixel), self._handle_width / 2 - 1, self._handle_width / 2 - 1) def _value_to_pixel(self, value: int) -> int: - value_percent = value / (self.max_value - self.min_value) + value_percent = value / self.max_value pixel = (self.height() - 2 * self._handle_width) * value_percent + self._handle_width return pixel def _pixel_to_value(self, pixel: int) -> int: pixel_percent = (pixel - self._handle_width) / (self.height() - 2 * self._handle_width) - return (self.max_value - self.min_value) * pixel_percent + return int(math.floor(self.max_value * pixel_percent)) def _is_on_handle(self, handle: RangeSliderHandle, y_pixel: int, direction=1) -> bool: handle_y_pixel = self._value_to_pixel(handle.value) @@ -139,5 +158,28 @@ class RangeSlider(QWidget): if self.selection_drag_range[0] <= value <= self.selection_drag_range[1]: self.selected_handle.value = value # print("%s, %s" %(self.lower_value.value, self.upper_value.value)) - self.value_changed.emit(self.lower_value.value, self.upper_value.value) + self._emit_value_changed() self.update() + self._update_tooltip() + + def set_range_start(self, value: int): + self.lower_value.value = value + self._emit_value_changed() + self.update() + + def set_range_end(self, value: int): + self.upper_value.value = value + self._emit_value_changed() + self.update() + + def _emit_value_changed(self): + # print(f"emit {str(self.lower_value.value)}, {str(self.upper_value.value)}") + self.value_changed.emit(str(self.lower_value.value), str(self.upper_value.value)) + + def _update_tooltip(self): + text = _("showing bytes {0} to {1} ({2})").format( + self.lower_value.value, + self.upper_value.value, + conversion.humanbytes(self.upper_value.value - self.lower_value.value)) + PluginRegistry.execute("update_status_bar", text) + self.setToolTip(text)