__ __ __ __ _____ _ _ _____ _ _ _ | \/ | \ \ / / | __ \ (_) | | / ____| | | | | | \ / |_ __\ V / | |__) | __ ___ ____ _| |_ ___ | (___ | |__ ___| | | | |\/| | '__|> < | ___/ '__| \ \ / / _` | __/ _ \ \___ \| '_ \ / _ \ | | | | | | |_ / . \ | | | | | |\ V / (_| | || __/ ____) | | | | __/ | | |_| |_|_(_)_/ \_\ |_| |_| |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1 if you need WebShell for Seo everyday contact me on Telegram Telegram Address : @jackleetFor_More_Tools:
# Orca # # Copyright 2023 Igalia, S.L. # Author: Joanmarie Diggs <[email protected]> # Based on the feature created by: # Author: Jose Vilmar <[email protected]> # Copyright 2010 Informal Informatica LTDA. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Boston MA 02110-1301 USA. # pylint: disable=wrong-import-position """Module for notification messages""" # This has to be the first non-docstring line in the module to make linters happy. from __future__ import annotations __id__ = "$Id$" __version__ = "$Revision$" __date__ = "$Date$" __copyright__ = "Copyright (c) 2023 Igalia, S.L." \ "Copyright (c) 2010 Informal Informatica LTDA." __license__ = "LGPL" import time from typing import Callable, Optional, TYPE_CHECKING import gi gi.require_version('Gtk', '3.0') from gi.repository import GObject from gi.repository import Gtk from . import cmdnames from . import debug from . import guilabels from . import input_event from . import keybindings from . import messages if TYPE_CHECKING: from .scripts import default class NotificationPresenter: """Provides access to the notification history.""" def __init__(self) -> None: self._gui: Optional[NotificationListGUI] = None self._handlers: dict[str, input_event.InputEventHandler] = self.get_handlers(True) self._bindings: keybindings.KeyBindings = keybindings.KeyBindings() self._max_size: int = 55 # The list is arranged with the most recent message being at the end of # the list. The current index is relative to, and used directly, with the # python list, i.e. self._notifications[-3] would return the third-to-last # notification message. self._notifications: list[tuple[str, float]] = [] self._current_index: int = -1 def get_bindings( self, refresh: bool = False, is_desktop: bool = True ) -> keybindings.KeyBindings: """Returns the notification-presenter keybindings.""" if refresh: msg = f"NOTIFICATION PRESENTER: Refreshing bindings. Is desktop: {is_desktop}" debug.print_message(debug.LEVEL_INFO, msg, True) self._setup_bindings() elif self._bindings.is_empty(): self._setup_bindings() return self._bindings def get_handlers(self, refresh: bool = False) -> dict[str, input_event.InputEventHandler]: """Returns the notification-presenter handlers.""" if refresh: msg = "NOTIFICATION PRESENTER: Refreshing handlers." debug.print_message(debug.LEVEL_INFO, msg, True) self._setup_handlers() return self._handlers def save_notification(self, message: str) -> None: """Adds message to the list of notification messages.""" tokens = ["NOTIFICATION PRESENTER: Adding '", message, "'."] debug.print_tokens(debug.LEVEL_INFO, tokens, True) to_remove = max(len(self._notifications) - self._max_size + 1, 0) self._notifications = self._notifications[to_remove:] self._notifications.append((message, time.time())) def clear_list(self) -> None: """Clears the notifications list.""" msg = "NOTIFICATION PRESENTER: Clearing list." debug.print_message(debug.LEVEL_INFO, msg, True) self._notifications = [] self._current_index = -1 def _setup_handlers(self) -> None: """Sets up the notification-presenter input event handlers.""" self._handlers = {} self._handlers["present_last_notification"] = \ input_event.InputEventHandler( self._present_last_notification, cmdnames.NOTIFICATION_MESSAGES_LAST) self._handlers["present_next_notification"] = \ input_event.InputEventHandler( self._present_next_notification, cmdnames.NOTIFICATION_MESSAGES_NEXT) self._handlers["present_previous_notification"] = \ input_event.InputEventHandler( self._present_previous_notification, cmdnames.NOTIFICATION_MESSAGES_PREVIOUS) self._handlers["show_notification_list"] = \ input_event.InputEventHandler( self._show_notification_list, cmdnames.NOTIFICATION_MESSAGES_LIST) msg = "NOTIFICATION PRESENTER: Handlers set up." debug.print_message(debug.LEVEL_INFO, msg, True) def _setup_bindings(self) -> None: """Sets up the notification-presenter key bindings.""" self._bindings = keybindings.KeyBindings() self._bindings.add( keybindings.KeyBinding( "", keybindings.DEFAULT_MODIFIER_MASK, keybindings.NO_MODIFIER_MASK, self._handlers["present_last_notification"])) self._bindings.add( keybindings.KeyBinding( "", keybindings.DEFAULT_MODIFIER_MASK, keybindings.NO_MODIFIER_MASK, self._handlers["present_next_notification"])) self._bindings.add( keybindings.KeyBinding( "", keybindings.DEFAULT_MODIFIER_MASK, keybindings.NO_MODIFIER_MASK, self._handlers["present_previous_notification"])) self._bindings.add( keybindings.KeyBinding( "", keybindings.DEFAULT_MODIFIER_MASK, keybindings.NO_MODIFIER_MASK, self._handlers["show_notification_list"])) msg = "NOTIFICATION PRESENTER: Bindings set up." debug.print_message(debug.LEVEL_INFO, msg, True) def _timestamp_to_string(self, timestamp: float) -> str: diff = time.time() - timestamp if diff < 60: return messages.secondsAgo(diff) if diff < 3600: minutes = round(diff / 60) return messages.minutesAgo(minutes) if diff < 86400: hours = round(diff / 3600) return messages.hoursAgo(hours) days = round(diff / 86400) return messages.daysAgo(days) def _present_last_notification( self, script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Presents the last notification.""" if not self._notifications: script.presentMessage(messages.NOTIFICATION_NO_MESSAGES) return True msg = "NOTIFICATION PRESENTER: Presenting last notification." debug.print_message(debug.LEVEL_INFO, msg, True) message, timestamp = self._notifications[-1] string = f"{message} {self._timestamp_to_string(timestamp)}" script.presentMessage(string) self._current_index = -1 return True def _present_previous_notification( self, script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Presents the previous notification.""" if not self._notifications: script.presentMessage(messages.NOTIFICATION_NO_MESSAGES) return True msg = ( f"NOTIFICATION PRESENTER: Presenting previous notification. " f"Current index: {self._current_index}" ) debug.print_message(debug.LEVEL_INFO, msg, True) # This is the first (oldest) message in the list. if self._current_index == 0 : script.presentMessage(messages.NOTIFICATION_LIST_TOP) message, timestamp = self._notifications[self._current_index] else: try: index = self._current_index - 1 message, timestamp = self._notifications[index] self._current_index -= 1 except IndexError: msg = "NOTIFICATION PRESENTER: Handling IndexError exception." debug.print_message(debug.LEVEL_INFO, msg, True) script.presentMessage(messages.NOTIFICATION_LIST_TOP) message, timestamp = self._notifications[self._current_index] string = f"{message} {self._timestamp_to_string(timestamp)}" script.presentMessage(string) return True def _present_next_notification( self, script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Presents the next notification.""" if not self._notifications: script.presentMessage(messages.NOTIFICATION_NO_MESSAGES) return True msg = ( f"NOTIFICATION PRESENTER: Presenting next notification. " f"Current index: {self._current_index}" ) debug.print_message(debug.LEVEL_INFO, msg, True) # This is the last (newest) message in the list. if self._current_index == -1: script.presentMessage(messages.NOTIFICATION_LIST_BOTTOM) message, timestamp = self._notifications[self._current_index] else: try: index = self._current_index + 1 message, timestamp = self._notifications[index] self._current_index += 1 except IndexError: msg = "NOTIFICATION PRESENTER: Handling IndexError exception." debug.print_message(debug.LEVEL_INFO, msg, True) script.presentMessage(messages.NOTIFICATION_LIST_BOTTOM) message, timestamp = self._notifications[self._current_index] string = f"{message} {self._timestamp_to_string(timestamp)}" script.presentMessage(string) return True def _show_notification_list( self, script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Opens a dialog with a list of the notifications.""" if not self._notifications: script.presentMessage(messages.NOTIFICATION_NO_MESSAGES) return True if self._gui: msg = "NOTIFICATION PRESENTER: Notification list already exists. Showing." debug.print_message(debug.LEVEL_INFO, msg, True) self._gui.show_gui() return True msg = "NOTIFICATION PRESENTER: Showing notification list." debug.print_message(debug.LEVEL_INFO, msg, True) rows = [(message, self._timestamp_to_string(timestamp)) \ for message, timestamp in reversed(self._notifications)] title = guilabels.notifications_count(len(self._notifications)) column_headers = [guilabels.NOTIFICATIONS_COLUMN_HEADER, guilabels.NOTIFICATIONS_RECEIVED_TIME] self._gui = NotificationListGUI( script, title, column_headers, rows, self.on_dialog_destroyed) self._gui.show_gui() return True def on_dialog_destroyed(self, _dialog: Gtk.Dialog) -> None: """Handler for the 'destroyed' signal of the dialog.""" self._gui = None class NotificationListGUI: """The dialog containing the notifications list.""" def __init__( self, script: default.Script, title: str, column_headers: list[str], rows: list[tuple[str, str]], destroyed_callback: Callable[[Gtk.Dialog], None] ): self._script: default.Script = script self._model: Optional[Gtk.ListStore] = None self._gui: Gtk.Dialog = self._create_dialog(title, column_headers, rows) self._gui.connect("destroy", destroyed_callback) def _create_dialog( self, title: str, column_headers: list[str], rows: list[tuple[str, str]] ) -> Gtk.Dialog: dialog = Gtk.Dialog(title, None, Gtk.DialogFlags.MODAL, (Gtk.STOCK_CLEAR, Gtk.ResponseType.APPLY, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)) dialog.set_default_size(600, 400) grid = Gtk.Grid() content_area = dialog.get_content_area() content_area.add(grid) scrolled_window = Gtk.ScrolledWindow() grid.add(scrolled_window) tree = Gtk.TreeView() tree.set_hexpand(True) tree.set_vexpand(True) scrolled_window.add(tree) cols = len(column_headers) * [GObject.TYPE_STRING] for i, header in enumerate(column_headers): cell = Gtk.CellRendererText() column = Gtk.TreeViewColumn(header, cell, text=i) tree.append_column(column) if header: column.set_sort_column_id(i) self._model = Gtk.ListStore(*cols) for row in rows: row_iter = self._model.append(None) for i, cell in enumerate(row): self._model.set_value(row_iter, i, cell) tree.set_model(self._model) dialog.connect("response", self.on_response) return dialog def on_response(self, _dialog: Gtk.Dialog, response: int) -> None: """The handler for the 'response' signal.""" if response == Gtk.ResponseType.CLOSE: self._gui.destroy() return if response == Gtk.ResponseType.APPLY and self._model is not None: self._model.clear() get_presenter().clear_list() self._script.presentMessage(messages.NOTIFICATION_NO_MESSAGES) time.sleep(1) self._gui.destroy() def show_gui(self) -> None: """Shows the notifications list dialog.""" self._gui.show_all() self._gui.present_with_time(time.time()) _presenter: NotificationPresenter = NotificationPresenter() def get_presenter() -> NotificationPresenter: """Returns the Notification Presenter""" return _presenter
| Name | Type | Size | Permission | Actions |
|---|---|---|---|---|
| __pycache__ | Folder | 0755 |
|
|
| backends | Folder | 0755 |
|
|
| scripts | Folder | 0755 |
|
|
| __init__.py | File | 115 B | 0644 |
|
| acss.py | File | 3.85 KB | 0644 |
|
| action_presenter.py | File | 8.65 KB | 0644 |
|
| ax_collection.py | File | 6.16 KB | 0644 |
|
| ax_component.py | File | 14.93 KB | 0644 |
|
| ax_document.py | File | 9.36 KB | 0644 |
|
| ax_event_synthesizer.py | File | 17.39 KB | 0644 |
|
| ax_hypertext.py | File | 8.36 KB | 0644 |
|
| ax_object.py | File | 47.84 KB | 0644 |
|
| ax_selection.py | File | 4.54 KB | 0644 |
|
| ax_table.py | File | 47.98 KB | 0644 |
|
| ax_text.py | File | 45.13 KB | 0644 |
|
| ax_utilities.py | File | 28.24 KB | 0644 |
|
| ax_utilities_application.py | File | 7.17 KB | 0644 |
|
| ax_utilities_collection.py | File | 86.79 KB | 0644 |
|
| ax_utilities_debugging.py | File | 10.12 KB | 0644 |
|
| ax_utilities_event.py | File | 32.78 KB | 0644 |
|
| ax_utilities_relation.py | File | 15.2 KB | 0644 |
|
| ax_utilities_role.py | File | 91.79 KB | 0644 |
|
| ax_utilities_state.py | File | 11.63 KB | 0644 |
|
| ax_value.py | File | 6.83 KB | 0644 |
|
| bookmarks.py | File | 11.95 KB | 0644 |
|
| braille.py | File | 74.03 KB | 0644 |
|
| braille_generator.py | File | 55.79 KB | 0644 |
|
| braille_rolenames.py | File | 10.23 KB | 0644 |
|
| brlmon.py | File | 6.53 KB | 0644 |
|
| brltablenames.py | File | 7.3 KB | 0644 |
|
| bypass_mode_manager.py | File | 4.79 KB | 0644 |
|
| caret_navigation.py | File | 19.51 KB | 0644 |
|
| chat.py | File | 32.03 KB | 0644 |
|
| clipboard.py | File | 20.45 KB | 0644 |
|
| cmdnames.py | File | 61.77 KB | 0644 |
|
| colornames.py | File | 39.22 KB | 0644 |
|
| debug.py | File | 3.95 KB | 0644 |
|
| debugging_tools_manager.py | File | 10.69 KB | 0644 |
|
| event_manager.py | File | 36.07 KB | 0644 |
|
| flat_review.py | File | 48.89 KB | 0644 |
|
| flat_review_finder.py | File | 20.2 KB | 0644 |
|
| flat_review_presenter.py | File | 45.94 KB | 0644 |
|
| focus_manager.py | File | 11.52 KB | 0644 |
|
| generator.py | File | 67.07 KB | 0644 |
|
| guilabels.py | File | 56.38 KB | 0644 |
|
| highlighter.py | File | 6.95 KB | 0644 |
|
| input_event.py | File | 30.05 KB | 0644 |
|
| input_event_manager.py | File | 35.66 KB | 0644 |
|
| keybindings.py | File | 24.87 KB | 0644 |
|
| keynames.py | File | 9.55 KB | 0644 |
|
| label_inference.py | File | 19.77 KB | 0644 |
|
| learn_mode_presenter.py | File | 14.72 KB | 0644 |
|
| liveregions.py | File | 25.77 KB | 0644 |
|
| mathsymbols.py | File | 88.65 KB | 0644 |
|
| messages.py | File | 152.28 KB | 0644 |
|
| mouse_review.py | File | 23.34 KB | 0644 |
|
| notification_presenter.py | File | 14.17 KB | 0644 |
|
| object_navigator.py | File | 13.24 KB | 0644 |
|
| object_properties.py | File | 33.86 KB | 0644 |
|
| orca.py | File | 9.83 KB | 0644 |
|
| orca_gtkbuilder.py | File | 5.42 KB | 0644 |
|
| orca_gui_navlist.py | File | 6.51 KB | 0644 |
|
| orca_gui_prefs.py | File | 141.9 KB | 0644 |
|
| orca_gui_profile.py | File | 3.98 KB | 0644 |
|
| orca_i18n.py | File | 3.13 KB | 0644 |
|
| orca_modifier_manager.py | File | 13.76 KB | 0644 |
|
| orca_platform.py | File | 1.43 KB | 0644 |
|
| phonnames.py | File | 2.76 KB | 0644 |
|
| pronunciation_dict.py | File | 2.55 KB | 0644 |
|
| script.py | File | 11.11 KB | 0644 |
|
| script_manager.py | File | 14.68 KB | 0644 |
|
| script_utilities.py | File | 64.21 KB | 0644 |
|
| settings.py | File | 10.66 KB | 0644 |
|
| settings_manager.py | File | 27.13 KB | 0644 |
|
| sleep_mode_manager.py | File | 5.04 KB | 0644 |
|
| sound.py | File | 5.51 KB | 0644 |
|
| sound_generator.py | File | 48.88 KB | 0644 |
|
| speech.py | File | 8.87 KB | 0644 |
|
| speech_and_verbosity_manager.py | File | 27.71 KB | 0644 |
|
| speech_generator.py | File | 163.53 KB | 0644 |
|
| speechdispatcherfactory.py | File | 24.68 KB | 0644 |
|
| speechserver.py | File | 8 KB | 0644 |
|
| spellcheck.py | File | 18.11 KB | 0644 |
|
| spiel.py | File | 25.59 KB | 0644 |
|
| ssml.py | File | 6.71 KB | 0644 |
|
| structural_navigation.py | File | 77.63 KB | 0644 |
|
| system_information_presenter.py | File | 7.44 KB | 0644 |
|
| table_navigator.py | File | 29.78 KB | 0644 |
|
| text_attribute_names.py | File | 27.31 KB | 0644 |
|
| where_am_i_presenter.py | File | 21.59 KB | 0644 |
|