add positions of hits to the range slider
This commit is contained in:
@@ -38,7 +38,8 @@ class FilterTask(QRunnable):
|
||||
on_before: Callable[[], None],
|
||||
on_finish: Callable[[], None],
|
||||
show_only_matches: bool,
|
||||
matches_separator: str
|
||||
matches_separator: str,
|
||||
zoned_plugin_registry: ZonedPluginRegistry
|
||||
):
|
||||
super(FilterTask, self).__init__()
|
||||
self.source_model = source_model
|
||||
@@ -53,6 +54,7 @@ class FilterTask(QRunnable):
|
||||
self.filter_match_found_listeners = filter_match_found_listeners
|
||||
self.show_only_matches = show_only_matches
|
||||
self.matches_separator = matches_separator
|
||||
self.zoned_plugin_registry = zoned_plugin_registry
|
||||
|
||||
def only_matches(self, line: str, regex: re.Pattern):
|
||||
result = ""
|
||||
@@ -87,7 +89,10 @@ class FilterTask(QRunnable):
|
||||
listener(-1, -1) # notify listeners that a new search started
|
||||
|
||||
hits_count = 0
|
||||
hits_positions: set[float] = set(())
|
||||
self.zoned_plugin_registry.execute("update_hit_positions", hits_positions)
|
||||
last_progress_report = time.time()
|
||||
source_file_size = self.source_model.byte_count()
|
||||
try:
|
||||
with open(self.source_model.get_file(), "rb") as source:
|
||||
source.seek(self.source_model.range_start)
|
||||
@@ -121,6 +126,12 @@ class FilterTask(QRunnable):
|
||||
target.write(line.encode("utf8"))
|
||||
hits_count = hits_count + 1
|
||||
|
||||
hits_positions_before = len(hits_positions)
|
||||
hits_positions.add(round(source_line_offset / source_file_size, 3))
|
||||
hits_positions_after = len(hits_positions)
|
||||
if hits_positions_before != hits_positions_after:
|
||||
self.zoned_plugin_registry.execute("update_hit_positions", hits_positions)
|
||||
|
||||
# sometime buffering can hide results for a while
|
||||
# We force a flush periodically.
|
||||
if line_count % 10000 == 0:
|
||||
@@ -350,6 +361,7 @@ class FilterWidget(QWidget):
|
||||
lambda: self.search_is_running.emit(True),
|
||||
lambda: self.search_is_running.emit(False),
|
||||
show_only_matches,
|
||||
self.matches_separator.text()
|
||||
self.matches_separator.text(),
|
||||
self._zoned_plugin_registry
|
||||
)
|
||||
QThreadPool.globalInstance().start(self.filter_task)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from PySide6.QtWidgets import *
|
||||
from PySide6.QtCore import *
|
||||
|
||||
from src.pluginbase import PluginBase
|
||||
from src.ui.bigtext.bigtext import BigText
|
||||
from src.plugins.logfile.filterviewsyncer import FilterViewSyncer
|
||||
from src.plugins.logfile.filterwidget import FilterWidget
|
||||
@@ -17,6 +18,7 @@ class FullTabWidget(Tab):
|
||||
self._model = model
|
||||
self._zoned_plugin_registry = zoned_plugin_registry
|
||||
self.file_view = BigText(model)
|
||||
self._zoned_plugin_registry.register_plugin("TabWidgetPlugin", TabWidgetPlugin(self.file_view))
|
||||
self.filter_hit_view = FilterWidget(self._model, self._zoned_plugin_registry)
|
||||
self.filter_view_syncer = FilterViewSyncer(self.file_view)
|
||||
self.filter_hit_view.add_line_click_listener(self.filter_view_syncer.click_listener)
|
||||
@@ -51,3 +53,12 @@ class FullTabWidget(Tab):
|
||||
# overriding abstract method
|
||||
def on_reveal(self):
|
||||
self.filter_hit_view.on_reveal()
|
||||
|
||||
|
||||
class TabWidgetPlugin(PluginBase):
|
||||
def __init__(self, file_view: BigText):
|
||||
super(TabWidgetPlugin, self).__init__()
|
||||
self._file_view = file_view
|
||||
|
||||
def update_hit_positions(self, hit_positions: set[float]):
|
||||
self._file_view.update_hit_positions(hit_positions)
|
||||
|
||||
@@ -119,6 +119,10 @@ class BigText(QWidget):
|
||||
def get_file(self):
|
||||
return self.model.get_file()
|
||||
|
||||
def update_hit_positions(self, hit_positions: set[float]):
|
||||
if self.range_limit:
|
||||
self.range_limit.update_hit_positions(hit_positions)
|
||||
|
||||
def add_line_click_listener(self, listener: Callable[[int], None]):
|
||||
"""
|
||||
:param listener: a callable, the parameter is the byte offset of the clicked line
|
||||
|
||||
@@ -4,7 +4,7 @@ from enum import Enum
|
||||
import PySide6
|
||||
from PySide6 import QtGui
|
||||
from PySide6.QtCore import QRect, QPoint, Signal
|
||||
from PySide6.QtGui import QPainter, Qt
|
||||
from PySide6.QtGui import QPainter, Qt, QColor, QPen
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from src.pluginregistry import PluginRegistry
|
||||
@@ -53,6 +53,7 @@ class RangeSlider(QWidget):
|
||||
self.selected_handle = None
|
||||
self.selection_drag_range = (self.min_value, self.max_value)
|
||||
self.drag_y_offset_in_handle = 0
|
||||
self._hit_positions: set[float] = set(())
|
||||
|
||||
def set_maximum(self, max: int):
|
||||
if self.max_value == max:
|
||||
@@ -65,12 +66,16 @@ class RangeSlider(QWidget):
|
||||
self.upper_value.value = max
|
||||
self._emit_value_changed()
|
||||
|
||||
def update_hit_positions(self, hit_positions: set[float]):
|
||||
# print(f"updated hit positions in range slider:{len(hit_positions)} -> {hit_positions}")
|
||||
self._hit_positions = hit_positions
|
||||
|
||||
def paintEvent(self, event: PySide6.QtGui.QPaintEvent) -> None:
|
||||
painter = QPainter(self)
|
||||
self._draw_background(painter)
|
||||
self._draw_hits(painter)
|
||||
self._draw_handle(painter, self.lower_value)
|
||||
self._draw_handle(painter, self.upper_value, direction=-1)
|
||||
|
||||
painter.end()
|
||||
|
||||
def _draw_background(self, painter: QPainter) -> None:
|
||||
@@ -111,6 +116,25 @@ class RangeSlider(QWidget):
|
||||
pixel = (self.height() - 2 * self._handle_width) * value_percent + self._handle_width
|
||||
return pixel
|
||||
|
||||
def _draw_hits(self, painter: QPainter) -> None:
|
||||
color = to_qcolor("000000")
|
||||
color.setAlpha(192)
|
||||
pen = QPen(color)
|
||||
pen.setWidth(1)
|
||||
painter.setPen(pen)
|
||||
|
||||
# compute where to draw a line and then deduplicate then, so that we don't draw lines multiple times
|
||||
# this is for performance and because we use transparency and drawing a line multiple times would make it
|
||||
# darker
|
||||
paint_at_y_positions: set[int] = set(())
|
||||
for hit_position in self._hit_positions:
|
||||
y = (self.height() - 2 * self._handle_width) * hit_position + self._handle_width
|
||||
y = round(y)
|
||||
paint_at_y_positions.add(y)
|
||||
|
||||
for y in paint_at_y_positions:
|
||||
painter.drawLine(2, y, 18, y)
|
||||
|
||||
def _pixel_to_value(self, pixel: int) -> int:
|
||||
pixel_percent = (pixel - self._handle_width) / (self.height() - 2 * self._handle_width)
|
||||
return int(math.floor(self.max_value * pixel_percent))
|
||||
|
||||
@@ -7,12 +7,22 @@ def is_hex_color(color: str):
|
||||
return re.match("[0-9a-f]{6}", color, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
def is_hex_color_with_alpha(color: str):
|
||||
return re.match("[0-9a-f]{8}", color, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
def to_qcolor(color: str):
|
||||
if is_hex_color(color):
|
||||
red = int(color[0:2], 16)
|
||||
green = int(color[2:4], 16)
|
||||
blue = int(color[4:6], 16)
|
||||
return QColor(red, green, blue)
|
||||
if is_hex_color_with_alpha(color):
|
||||
red = int(color[0:2], 16)
|
||||
green = int(color[2:4], 16)
|
||||
blue = int(color[4:6], 16)
|
||||
alpha = int(color[6:8], 16)
|
||||
return QColor(red, green, blue, alpha)
|
||||
elif color in QColor().colorNames():
|
||||
return QColor(color)
|
||||
return QColor(255, 255, 255)
|
||||
|
||||
Reference in New Issue
Block a user