Update some system messaging

This commit is contained in:
Raoul Snyman 2023-08-27 06:33:58 +00:00 committed by Tim Bentley
parent 23c8d784a5
commit 96a6f2ab64
6 changed files with 86 additions and 50 deletions

View File

@ -25,7 +25,7 @@ import os
from PyQt5 import QtWidgets
from openlp.core.state import State
from openlp.core.state import State, MessageType
from openlp.core.common import extension_loader
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate, UiStrings
@ -169,13 +169,16 @@ class PluginManager(RegistryBase, LogMixin, RegistryProperties):
if uninitialised_plugins:
display_text = translate('OpenLP.PluginManager', 'Unable to initialise the following plugins:') + \
'\n\n'.join(uninitialised_plugins) + '\n\n'
error_text = State().get_text()
error_text = State().get_text(MessageType.Error)
info_text = State().get_text(MessageType.Information)
if error_text:
display_text = display_text + error_text + '\n'
if display_text:
display_text = display_text + translate('OpenLP.PluginManager', 'See the log file for more details')
display_text = display_text + error_text + '\n' + \
translate('OpenLP.PluginManager', 'See the log file for more details')
QtWidgets.QMessageBox.critical(None, UiStrings().Error, display_text,
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
if info_text:
QtWidgets.QMessageBox.information(None, UiStrings().Error, info_text,
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
def finalise_plugins(self):
"""

View File

@ -26,30 +26,38 @@ All the core functions of the OpenLP application including the GUI, settings, lo
contained within the openlp.core module.
"""
import logging
from enum import IntEnum
from openlp.core.common import Singleton
from openlp.core.common.registry import Registry
from openlp.core.common.mixins import LogMixin
from openlp.core.lib.plugin import PluginStatus
from openlp.core.lib.plugin import Plugin, PluginStatus
log = logging.getLogger()
class MessageType(IntEnum):
Error = 1
Warning = 2
Information = 3
class StateModule(LogMixin):
def __init__(self):
"""
Holder of State information per module
"""
super(StateModule, self).__init__()
self.name = None
self.order = 0
self.is_plugin = None
self.status = PluginStatus.Inactive
self.pass_preconditions = False
self.requires = None
self.required_by = None
self.text = None
self.name: str | None = None
self.order: int = 0
self.is_plugin: bool = False
self.status: PluginStatus = PluginStatus.Inactive
self.pass_preconditions: bool = False
self.requires: str | None = None
self.required_by: list | None = None
self.text: str | None = None
self.message_type: MessageType = MessageType.Error
class State(LogMixin, metaclass=Singleton):
@ -60,7 +68,8 @@ class State(LogMixin, metaclass=Singleton):
def save_settings(self):
pass
def add_service(self, name, order, is_plugin=False, status=PluginStatus.Active, requires=None):
def add_service(self, name: str, order: int, is_plugin: bool = False, status: PluginStatus = PluginStatus.Active,
requires: str | None = None):
"""
Add a module to the array and load dependencies. There will only be one item per module
:param name: Module name
@ -83,7 +92,7 @@ class State(LogMixin, metaclass=Singleton):
if requires not in self.modules[requires].required_by:
self.modules[requires].required_by.append(name)
def missing_text(self, name, text):
def missing_text(self, name: str, text: str, type_: MessageType = MessageType.Error):
"""
Updates the preconditions state of a module
@ -92,31 +101,32 @@ class State(LogMixin, metaclass=Singleton):
:return:
"""
self.modules[name].text = text
self.modules[name].message_type = type_
def get_text(self):
def get_text(self, type_: MessageType | None = None) -> str:
"""
return an string of error text
:return: a string of text
"""
error_text = ''
all_text = ''
for mod in self.modules:
if self.modules[mod].text:
error_text = error_text + self.modules[mod].text + '\n'
return error_text
if self.modules[mod].text and (not type_ or self.modules[mod].message_type == type_):
all_text = all_text + self.modules[mod].text + '\n'
return all_text
def update_pre_conditions(self, name, status):
def update_pre_conditions(self, name: str, is_active: bool):
"""
Updates the preconditions state of a module
:param name: Module name
:param status: Module new status
:param is_active: Module new status
:return:
"""
self.modules[name].pass_preconditions = status
self.modules[name].pass_preconditions = is_active
if self.modules[name].is_plugin:
plugin = Registry().get('{mod}_plugin'.format(mod=name))
if status:
self.log_debug('Plugin {plugin} active'.format(plugin=str(plugin.name)))
plugin = Registry().get(f'{name}_plugin')
if is_active:
self.log_debug(f'Plugin {plugin.name} active')
plugin.set_status()
else:
plugin.status = PluginStatus.Disabled
@ -136,10 +146,10 @@ class State(LogMixin, metaclass=Singleton):
mdl[pl] = self.modules[pl]
self.modules = mdl
def is_module_active(self, name):
def is_module_active(self, name) -> bool:
return self.modules[name].status == PluginStatus.Active
def check_preconditions(self, name):
def check_preconditions(self, name: str) -> bool:
"""
Checks if a modules preconditions have been met.
@ -157,7 +167,7 @@ class State(LogMixin, metaclass=Singleton):
# Module is missing so therefore not found.
return False
def list_plugins(self):
def list_plugins(self) -> list[Plugin]:
"""
Return a list of plugins
:return: an array of plugins
@ -165,5 +175,5 @@ class State(LogMixin, metaclass=Singleton):
plugins = []
for mod in self.modules:
if self.modules[mod].is_plugin:
plugins.append(Registry().get('{mod}_plugin'.format(mod=mod)))
plugins.append(Registry().get(f'{mod}_plugin'))
return plugins

View File

@ -1039,12 +1039,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
and (datetime.now() - self.screen_change_timestamp).seconds < 5
should_show_messagebox = self.settings_form.isHidden() and not has_shown_messagebox_recently
if should_show_messagebox:
QtWidgets.QMessageBox.warning(self, translate('OpenLP.MainWindow', 'Screen setup has changed'),
translate('OpenLP.MainWindow',
'The screen setup has changed. '
'OpenLP will try to automatically select a display screen, but '
'you should consider updating the screen settings.'),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
QtWidgets.QMessageBox.information(self, translate('OpenLP.MainWindow', 'Screen setup has changed'),
translate('OpenLP.MainWindow',
'The screen setup has changed. OpenLP will try to '
'automatically select a display screen, but '
'you should consider updating the screen settings.'),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
self.screen_change_timestamp = datetime.now()
self.application.set_busy_cursor()
self.renderer.resize(self.live_controller.screens.current.display_geometry.size())

View File

@ -42,7 +42,7 @@ from openlp.core.common.registry import Registry, RegistryBase
from openlp.core.display.window import DisplayWindow
from openlp.core.lib.serviceitem import ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box, warning_message_box
from openlp.core.state import State
from openlp.core.state import State, MessageType
from openlp.core.ui import DisplayControllerType, HideMode
from openlp.core.ui.slidecontroller import SlideController
from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path, parse_stream_path, \
@ -116,6 +116,7 @@ class MediaController(QtWidgets.QWidget, RegistryBase, LogMixin, RegistryPropert
else:
if hasattr(self.main_window, 'splash') and self.main_window.splash.isVisible():
self.main_window.splash.hide()
message_type = MessageType.Error
generic_message = translate('OpenLP.MediaController',
'OpenLP requires the following libraries in order to show videos and other '
'media, but they are not installed. Please install these libraries to enable '
@ -125,8 +126,11 @@ class MediaController(QtWidgets.QWidget, RegistryBase, LogMixin, RegistryPropert
'repository: https://rpmfusion.org/')
if is_macosx():
message = translate('OpenLP.MediaController',
'macOS is missing VLC. Please download and install from the VLC web site: '
'https://www.videolan.org/vlc/')
'<strong>OpenLP could not detect VLC.</strong> You will not be able to play media '
'without it. Please download and install from the VLC web site: '
'<a href="https://www.videolan.org/vlc/download-macosx.html">'
'https://www.videolan.org/vlc/</a>')
message_type = MessageType.Information
else:
packages = []
if not has_vlc:
@ -136,7 +140,7 @@ class MediaController(QtWidgets.QWidget, RegistryBase, LogMixin, RegistryPropert
message = generic_message + '\n\n' + ', '.join(packages)
if not has_vlc and is_linux(distro='fedora'):
message += '\n\n' + fedora_rpmfusion
State().missing_text('media_live', message)
State().missing_text('media_live', message, message_type)
return True
def bootstrap_post_set_up(self):

View File

@ -19,7 +19,7 @@
##########################################################################
from unittest.mock import MagicMock
from openlp.core.state import State
from openlp.core.state import State, MessageType
from openlp.core.common.registry import Registry
from openlp.core.lib.plugin import PluginStatus
@ -158,10 +158,12 @@ def test_missing_text(state):
State().modules['test'] = MagicMock()
# WHEN: missing_text() is called
State().missing_text('test', 'Test test')
State().missing_text('test', 'Test test', MessageType.Information)
# THEN: The text is set
assert State().modules['test'].text == 'Test test', 'The text on the module should have been set'
assert State().modules['test'].message_type == MessageType.Information, \
'The message type on the module should have been set'
def test_get_text(state):
@ -169,7 +171,8 @@ def test_get_text(state):
Test that the get_text() method returns the text of all the states
"""
# GIVEN: Some states with text
State().modules.update({'test1': MagicMock(text='Test 1'), 'test2': MagicMock(text='Test 2')})
State().modules.update({'test1': MagicMock(text='Test 1', message_type=MessageType.Error),
'test2': MagicMock(text='Test 2', message_type=MessageType.Information)})
# WHEN: get_text() is called
result = State().get_text()
@ -178,6 +181,21 @@ def test_get_text(state):
assert result == 'Test 1\nTest 2\n', 'The full text is returned'
def test_get_text_single_type(state):
"""
Test that the get_text() method returns the text of only that particular message type
"""
# GIVEN: Some states with text
State().modules.update({'test1': MagicMock(text='Test 1', message_type=MessageType.Error),
'test2': MagicMock(text='Test 2', message_type=MessageType.Information)})
# WHEN: get_text() is called
result = State().get_text(MessageType.Information)
# THEN: The correct text is returned
assert result == 'Test 2\n', 'Only the information text is returned'
def test_check_preconditions_no_required(state):
"""
Test that the check_preconditions() method returns the correct attribute when there are no requirements

View File

@ -757,8 +757,8 @@ def test_load_settings_view_mode_live(mocked_view_mode, main_window, settings):
mocked_view_mode.assert_called_with(True, True, True, True, False, True)
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
def test_screen_changed_modal(mocked_warning, main_window):
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.information')
def test_screen_changed_modal(mocked_information: MagicMock, main_window: MainWindow):
"""
Test that the screen changed modal is shown whether a 'config_screen_changed' event is dispatched
"""
@ -771,11 +771,12 @@ def test_screen_changed_modal(mocked_warning, main_window):
Registry().execute('config_screen_changed')
# THEN: The modal should be called once
mocked_warning.assert_called_once()
mocked_information.assert_called_once()
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
def test_screen_changed_modal_sets_timestamp_after_blocking_on_modal(mocked_warning, main_window):
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.information')
def test_screen_changed_modal_sets_timestamp_after_blocking_on_modal(mocked_information: MagicMock,
main_window: MainWindow):
"""
Test that the screen changed modal latest shown timestamp is set after showing warning message, so
that duplicate modals due to event spamming on 'config_screen_changed' in less than 5 seconds is mitigated.
@ -790,7 +791,7 @@ def test_screen_changed_modal_sets_timestamp_after_blocking_on_modal(mocked_warn
# THEN: main_window.screen_change_timestamp should have a timestamp, indicating that timestamp is set after
# the blocking modal is shown.
mocked_warning.assert_called_once()
mocked_information.assert_called_once()
assert main_window.screen_change_timestamp is not None