xref: /aosp_15_r20/external/pigweed/pw_console/py/pw_console/filter_toolbar.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2021 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""LogPane FilterToolbar class."""
15
16from __future__ import annotations
17import functools
18from typing import TYPE_CHECKING
19
20from prompt_toolkit.filters import Condition
21from prompt_toolkit.layout import (
22    ConditionalContainer,
23    FormattedTextControl,
24    VSplit,
25    Window,
26    WindowAlign,
27    HorizontalAlign,
28)
29from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
30
31from pw_console.style import (
32    get_button_style,
33    get_toolbar_style,
34)
35from pw_console.widgets import (
36    mouse_handlers,
37    to_keybind_indicator,
38)
39
40if TYPE_CHECKING:
41    from pw_console.log_pane import LogPane
42
43
44class FilterToolbar(ConditionalContainer):
45    """Container showing each filter applied in order."""
46
47    TOOLBAR_HEIGHT = 1
48
49    def mouse_handler_delete_filter(self, filter_text, mouse_event: MouseEvent):
50        """Delete the given log filter."""
51        if mouse_event.event_type == MouseEventType.MOUSE_UP:
52            self.log_pane.log_view.delete_filter(filter_text)
53            return None
54        return NotImplemented
55
56    def get_left_fragments(self):
57        """Return formatted text tokens for display."""
58        separator = ('', '  ')
59        space = ('', ' ')
60        fragments = [('class:filter-bar-title', ' Filters '), separator]
61
62        button_style = get_button_style(self.log_pane)
63
64        for filter_text, log_filter in self.log_pane.log_view.filters.items():
65            fragments.append(('class:filter-bar-delimiter', '<'))
66
67            if log_filter.invert:
68                fragments.append(('class:filter-bar-setting', 'NOT '))
69
70            if log_filter.field:
71                fragments.append(('class:filter-bar-setting', log_filter.field))
72                fragments.append(space)
73
74            fragments.append(('', filter_text))
75            fragments.append(space)
76
77            fragments.append(
78                (
79                    button_style + ' class:filter-bar-delete',
80                    ' (X) ',
81                    functools.partial(
82                        self.mouse_handler_delete_filter, filter_text
83                    ),
84                )
85            )  # type: ignore
86            fragments.append(('class:filter-bar-delimiter', '>'))
87
88            fragments.append(separator)
89        return fragments
90
91    def get_center_fragments(self):
92        """Return formatted text tokens for display."""
93        clear_filters = functools.partial(
94            mouse_handlers.on_click,
95            self.log_pane.log_view.clear_filters,
96        )
97
98        button_style = get_button_style(self.log_pane)
99
100        return to_keybind_indicator(
101            'Ctrl-Alt-r',
102            'Clear Filters',
103            clear_filters,
104            base_style=button_style,
105        )
106
107    def __init__(self, log_pane: LogPane):
108        self.log_pane = log_pane
109        left_bar_control = FormattedTextControl(self.get_left_fragments)
110        left_bar_window = Window(
111            content=left_bar_control,
112            align=WindowAlign.LEFT,
113            dont_extend_width=True,
114        )
115        center_bar_control = FormattedTextControl(self.get_center_fragments)
116        center_bar_window = Window(
117            content=center_bar_control,
118            align=WindowAlign.LEFT,
119            dont_extend_width=False,
120        )
121        super().__init__(
122            VSplit(
123                [
124                    left_bar_window,
125                    center_bar_window,
126                ],
127                style=functools.partial(
128                    get_toolbar_style, self.log_pane, dim=True
129                ),
130                height=1,
131                align=HorizontalAlign.LEFT,
132            ),
133            # Only show if filtering is enabled.
134            filter=Condition(lambda: self.log_pane.log_view.filtering_on),
135        )
136