diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 669792c06..fed6c4e5b 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -149,6 +149,7 @@ class Settings(QtCore.QSettings): 'core/auto preview': False, 'core/audio start paused': True, 'core/auto unblank': False, + 'core/click live slide to unblank': False, 'core/blank warning': False, 'core/ccli number': '', 'core/has run wizard': False, diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index c7c84f912..2edea93cf 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -488,6 +488,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties): 'You must select one or more items to preview.')) else: log.debug('%s Preview requested' % self.plugin.name) + Registry().set_flag('has doubleclick added item to service', False) service_item = self.build_service_item() if service_item: service_item.from_plugin = True diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 8d7bd9521..ca91e882a 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -257,7 +257,7 @@ class AdvancedTab(SettingsTab): self.data_directory_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Data Location')) self.recent_label.setText(translate('OpenLP.AdvancedTab', 'Number of recent service files to display:')) self.media_plugin_check_box.setText(translate('OpenLP.AdvancedTab', - 'Open the last used Library category on startup')) + 'Open the last used Library tab on startup')) self.double_click_live_check_box.setText(translate('OpenLP.AdvancedTab', 'Double-click to send items straight to Live')) self.single_click_preview_check_box.setText(translate('OpenLP.AdvancedTab', @@ -265,7 +265,7 @@ class AdvancedTab(SettingsTab): self.single_click_service_preview_check_box.setText(translate('OpenLP.AdvancedTab', 'Preview items when clicked in Service')) self.expand_service_item_check_box.setText(translate('OpenLP.AdvancedTab', - 'Expand new Service items on creation')) + 'Expand new service items on creation')) self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab', 'Max height for non-text slides\nin slide controller:')) self.slide_max_height_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Disabled')) diff --git a/openlp/core/ui/exceptiondialog.py b/openlp/core/ui/exceptiondialog.py index 443c22bd8..7341287c7 100644 --- a/openlp/core/ui/exceptiondialog.py +++ b/openlp/core/ui/exceptiondialog.py @@ -106,7 +106,7 @@ class Ui_ExceptionDialog(object): translate('OpenLP.ExceptionDialog', '{first_part}' 'No email app? You can save this ' 'information to a file and
' - 'send it from your mail on browser via an attachement.

' + 'send it from your mail on browser via an attachment.

' 'Thank you for being part of making OpenLP better!
' ).format(first_part=exception_part1)) self.send_report_button.setText(translate('OpenLP.ExceptionDialog', 'Send E-Mail')) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index a3036b960..2122acfaa 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -197,13 +197,18 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): """ count = int(20 - len(self.description_text_edit.toPlainText())) if count < 0: - count = 0 self.__button_state(True) + self.description_word_count.setText( + translate('OpenLP.ExceptionDialog', 'Thank you for your description!')) + elif count == 20: + self.__button_state(False) + self.description_word_count.setText( + translate('OpenLP.ExceptionDialog', 'Tell us what you were doing when this happened.')) else: self.__button_state(False) - self.description_word_count.setText( - translate('OpenLP.ExceptionDialog', '{count} characters remaining from the minimum description.' - ).format(count=count)) + self.description_word_count.setText( + translate('OpenLP.ExceptionDialog', 'Please enter a more detailed description of the situation' + )) def on_attach_file_button_clicked(self): """ diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index 3abe8eb7b..463aad73f 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -209,6 +209,9 @@ class GeneralTab(SettingsTab): self.auto_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box) self.auto_unblank_check_box.setObjectName('auto_unblank_check_box') self.settings_layout.addRow(self.auto_unblank_check_box) + self.click_live_slide_to_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box) + self.click_live_slide_to_unblank_check_box.setObjectName('click_live_slide_to_unblank') + self.settings_layout.addRow(self.click_live_slide_to_unblank_check_box) self.auto_preview_check_box = QtWidgets.QCheckBox(self.settings_group_box) self.auto_preview_check_box.setObjectName('auto_preview_check_box') self.settings_layout.addRow(self.auto_preview_check_box) @@ -258,6 +261,8 @@ class GeneralTab(SettingsTab): self.settings_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Settings')) self.save_check_service_check_box.setText(translate('OpenLP.GeneralTab', 'Prompt to save before starting a new service')) + self.click_live_slide_to_unblank_check_box.setText(translate('OpenLP.GeneralTab', + 'Unblank display when changing slide in Live')) self.auto_unblank_check_box.setText(translate('OpenLP.GeneralTab', 'Unblank display when sending ' 'items to Live')) self.auto_preview_check_box.setText(translate('OpenLP.GeneralTab', @@ -293,6 +298,7 @@ class GeneralTab(SettingsTab): self.password_edit.setText(settings.value('songselect password')) self.save_check_service_check_box.setChecked(settings.value('save prompt')) self.auto_unblank_check_box.setChecked(settings.value('auto unblank')) + self.click_live_slide_to_unblank_check_box.setChecked(settings.value('click live slide to unblank')) self.display_on_monitor_check.setChecked(self.screens.display) self.warning_check_box.setChecked(settings.value('blank warning')) self.auto_open_check_box.setChecked(settings.value('auto open')) @@ -337,6 +343,7 @@ class GeneralTab(SettingsTab): settings.setValue('update check', self.check_for_updates_check_box.isChecked()) settings.setValue('save prompt', self.save_check_service_check_box.isChecked()) settings.setValue('auto unblank', self.auto_unblank_check_box.isChecked()) + settings.setValue('click live slide to unblank', self.click_live_slide_to_unblank_check_box.isChecked()) settings.setValue('auto preview', self.auto_preview_check_box.isChecked()) settings.setValue('loop delay', self.timeout_spin_box.value()) settings.setValue('ccli number', self.number_edit.displayText()) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 57a510015..9f1b8122d 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -431,13 +431,13 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', 'Export settings to a *.config file.')) self.settings_export_item.setText(translate('OpenLP.MainWindow', 'Settings')) self.settings_import_item.setStatusTip( - translate('OpenLP.MainWindow', 'Import OpenLP settings from a *.config file previously exported from ' - 'this or an another machine.')) + translate('OpenLP.MainWindow', 'Import settings from a *.config file previously exported from ' + 'this or another machine.')) self.settings_import_item.setText(translate('OpenLP.MainWindow', 'Settings')) - self.view_projector_manager_item.setText(translate('OPenLP.MainWindow', '&Projectors')) + self.view_projector_manager_item.setText(translate('OpenLP.MainWindow', '&Projectors')) self.view_projector_manager_item.setToolTip(translate('OpenLP.MainWindow', 'Hide or show Projectors.')) self.view_projector_manager_item.setStatusTip(translate('OpenLP.MainWindow', - 'Toggle the visibility of the Projectors.')) + 'Toggle visibility of the Projectors.')) self.view_media_manager_item.setText(translate('OpenLP.MainWindow', 'L&ibrary')) self.view_media_manager_item.setToolTip(translate('OpenLP.MainWindow', 'Hide or show the Library.')) self.view_media_manager_item.setStatusTip(translate('OpenLP.MainWindow', @@ -445,22 +445,22 @@ class Ui_MainWindow(object): self.view_theme_manager_item.setText(translate('OpenLP.MainWindow', '&Themes')) self.view_theme_manager_item.setToolTip(translate('OpenLP.MainWindow', 'Hide or show themes')) self.view_theme_manager_item.setStatusTip(translate('OpenLP.MainWindow', - 'Toggle the visibility of the Themes.')) + 'Toggle visibility of the Themes.')) self.view_service_manager_item.setText(translate('OpenLP.MainWindow', '&Service')) self.view_service_manager_item.setToolTip(translate('OpenLP.MainWindow', 'Hide or show Service.')) self.view_service_manager_item.setStatusTip(translate('OpenLP.MainWindow', - 'Toggle the visibility of the Service.')) + 'Toggle visibility of the Service.')) self.view_preview_panel.setText(translate('OpenLP.MainWindow', '&Preview')) self.view_preview_panel.setToolTip(translate('OpenLP.MainWindow', 'Hide or show Preview.')) self.view_preview_panel.setStatusTip( - translate('OpenLP.MainWindow', 'Toggle the visibility of the Preview.')) + translate('OpenLP.MainWindow', 'Toggle visibility of the Preview.')) self.view_live_panel.setText(translate('OpenLP.MainWindow', 'Li&ve')) self.view_live_panel.setToolTip(translate('OpenLP.MainWindow', 'Hide or show Live')) self.lock_panel.setText(translate('OpenLP.MainWindow', 'L&ock visibility of the panels')) self.lock_panel.setStatusTip(translate('OpenLP.MainWindow', 'Lock visibility of the panels.')) - self.view_live_panel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the Live.')) + self.view_live_panel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle visibility of the Live.')) self.settings_plugin_list_item.setText(translate('OpenLP.MainWindow', '&Manage Plugins')) - self.settings_plugin_list_item.setStatusTip(translate('OpenLP.MainWindow', 'You can activate or disable plugins' + self.settings_plugin_list_item.setStatusTip(translate('OpenLP.MainWindow', 'You can enable and disable plugins ' 'from here.')) self.about_item.setText(translate('OpenLP.MainWindow', '&About')) self.about_item.setStatusTip(translate('OpenLP.MainWindow', 'More information about OpenLP.')) @@ -489,9 +489,9 @@ class Ui_MainWindow(object): self.update_theme_images.setText(translate('OpenLP.MainWindow', 'Update Theme Images')) self.update_theme_images.setStatusTip(translate('OpenLP.MainWindow', 'Update the preview images for all themes.')) - self.mode_default_item.setText(translate('OpenLP.MainWindow', '&Default')) - self.mode_default_item.setStatusTip(translate('OpenLP.MainWindow', 'Reset the interface layout back to the ' - 'default settings.')) + self.mode_default_item.setText(translate('OpenLP.MainWindow', '&Show all')) + self.mode_default_item.setStatusTip(translate('OpenLP.MainWindow', 'Reset the interface back to the ' + 'default layout and show all the panels.')) self.mode_setup_item.setText(translate('OpenLP.MainWindow', '&Setup')) self.mode_setup_item.setStatusTip(translate('OpenLP.MainWindow', 'Use layout that focuses on setting' ' up the Service.')) @@ -957,7 +957,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties): self, translate('OpenLP.MainWindow', 'Export Settings File'), '', - translate('OpenLP.MainWindow', 'Exported OpenLP Settings (*.conf)')) + translate('OpenLP.MainWindow', 'OpenLP Settings (*.conf)')) if not export_file_name: return # Make sure it's a .conf file. diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index df2f72765..0c2a4c0d8 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -87,6 +87,8 @@ class DisplayController(QtWidgets.QWidget): self.is_live = False self.display = None self.controller_type = None + Registry().set_flag('has doubleclick added item to service', True) + Registry().set_flag('replace service manager item', False) def send_to_plugins(self, *args): """ @@ -800,12 +802,15 @@ class SlideController(DisplayController, RegistryProperties): def replace_service_manager_item(self, item): """ - Replacement item following a remote edit + Replacement item following a remote edit. + This action also takes place when a song that is sent to live from Service Manager is edited. :param item: The current service item """ if item == self.service_item: + Registry().set_flag('replace service manager item', True) self._process_item(item, self.preview_widget.current_slide_number()) + Registry().set_flag('replace service manager item', False) def add_service_manager_item(self, item, slide_no): """ @@ -973,9 +978,10 @@ class SlideController(DisplayController, RegistryProperties): def on_slide_unblank(self): """ - Handle the slidecontroller unblank event + Handle the slidecontroller unblank event. """ - self.on_blank_display(False) + if not Registry().get_flag('replace service manager item') is True: + self.on_blank_display(False) def on_blank_display(self, checked=None): """ @@ -1106,6 +1112,11 @@ class SlideController(DisplayController, RegistryProperties): self.log_debug('Could not get lock in slide_selected after waiting %f, skip to avoid deadlock.' % timeout) return + # If "click live slide to unblank" is enabled, unblank the display. And start = Item is sent to Live. + # Note: If this if statement is placed at the bottom of this function instead of top slide transitions are lost. + if self.is_live and Settings().value('core/click live slide to unblank'): + if not start: + Registry().execute('slidecontroller_live_unblank') row = self.preview_widget.current_slide_number() old_selected_row = self.selected_row self.selected_row = 0 @@ -1288,6 +1299,8 @@ class SlideController(DisplayController, RegistryProperties): self.play_slides_once.setText(UiStrings().PlaySlidesToEnd) self.play_slides_menu.setDefaultAction(self.play_slides_loop) self.play_slides_once.setChecked(False) + if Settings().value('core/click live slide to unblank'): + Registry().execute('slidecontroller_live_unblank') else: self.play_slides_loop.setIcon(build_icon(':/media/media_time.png')) self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop) @@ -1311,6 +1324,8 @@ class SlideController(DisplayController, RegistryProperties): self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop) self.play_slides_menu.setDefaultAction(self.play_slides_once) self.play_slides_loop.setChecked(False) + if Settings().value('core/click live slide to unblank'): + Registry().execute('slidecontroller_live_unblank') else: self.play_slides_once.setIcon(build_icon(':/media/media_time')) self.play_slides_once.setText(UiStrings().PlaySlidesToEnd) @@ -1365,7 +1380,7 @@ class SlideController(DisplayController, RegistryProperties): Triggered when a preview slide item is doubleclicked """ if self.service_item: - if Settings().value('advanced/double click live'): + if Settings().value('advanced/double click live') and Settings().value('core/auto unblank'): # Live and Preview have issues if we have video or presentations # playing in both at the same time. if self.service_item.is_command(): @@ -1374,8 +1389,13 @@ class SlideController(DisplayController, RegistryProperties): if self.service_item.is_media(): self.on_media_close() self.on_go_live() - else: + # If ('advanced/double click live') is not enabled, double clicking preview adds the item to Service. + # Prevent same item in preview from being sent to Service multiple times. + # Changing the preview slide resets this flag to False. + # Do note that this still allows to add item to Service multiple times if icon is clicked. + elif not Registry().get_flag('has doubleclick added item to service') is True: self.on_preview_add_to_service() + Registry().set_flag('has doubleclick added item to service', True) def on_go_live(self, field=None): """ diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index d65ac4432..dc196fb59 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -133,7 +133,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): disable_optical_button_text = True optical_button_text = translate('MediaPlugin.MediaItem', 'Load CD/DVD') optical_button_tooltip = translate('MediaPlugin.MediaItem', - 'CD/DVD Playback is only supported if VLC is installed and enabled.') + 'CD/DVD playback is only supported if VLC is installed and enabled.') self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=self.optical_icon, text=optical_button_text, tooltip=optical_button_tooltip, diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 097b9dc38..c12f1b0fb 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -26,7 +26,7 @@ import os from PyQt5 import QtCore -from openlp.core.common import Registry +from openlp.core.common import Registry, Settings from openlp.core.ui import HideMode from openlp.core.lib import ServiceItemContext from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES @@ -419,6 +419,8 @@ class MessageListener(object): is_live = message[1] if is_live: self.live_handler.next() + if Settings().value('core/click live slide to unblank'): + Registry().execute('slidecontroller_live_unblank') else: self.preview_handler.next() @@ -431,6 +433,8 @@ class MessageListener(object): is_live = message[1] if is_live: self.live_handler.previous() + if Settings().value('core/click live slide to unblank'): + Registry().execute('slidecontroller_live_unblank') else: self.preview_handler.previous() diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index 057ac9616..6a0aab211 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -125,11 +125,11 @@ class PresentationTab(SettingsTab): translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden')) self.ppt_slide_click_check_box.setText( translate('PresentationPlugin.PresentationTab', - 'Clicking on current slide advances to the next effect')) + 'Clicking on the current slide advances to the next effect')) self.ppt_window_check_box.setText( translate('PresentationPlugin.PresentationTab', 'Let PowerPoint control the size and monitor of the presentations\n' - '(This may fixes PowerPoint scaling issues in Windows 8 and 10)')) + '(This may fix PowerPoint scaling issues in Windows 8 and 10)')) self.pdf_program_check_box.setText( translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:')) diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index 9b757a8ed..83c547df9 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -713,6 +713,52 @@ class TestSlideController(TestCase): slide_controller.theme_screen, slide_controller.blank_screen ]) + @patch('openlp.core.ui.slidecontroller.Settings') + def on_preview_double_click_unblank_display_test(self, MockedSettings): + # GIVEN: A slide controller, actions needed, settins set to True. + slide_controller = SlideController(None) + mocked_settings = MagicMock() + mocked_settings.return_value = True + MockedSettings.return_value = mocked_settings + slide_controller.service_item = MagicMock() + slide_controller.service_item.is_media = MagicMock() + slide_controller.on_media_close = MagicMock() + slide_controller.on_go_live = MagicMock() + slide_controller.on_preview_add_to_service = MagicMock() + slide_controller.media_reset = MagicMock() + Registry.create() + Registry().set_flag('has doubleclick added item to service', True) + + # WHEN: on_preview_double_click is called + slide_controller.on_preview_double_click() + + # THEN: The call to addActions should be correct + self.assertEqual(1, slide_controller.on_go_live.call_count, 'on_go_live should have been called once.') + self.assertEqual(0, slide_controller.on_preview_add_to_service.call_count, 'Should have not been called.') + + @patch('openlp.core.ui.slidecontroller.Settings') + def on_preview_double_click_add_to_service_test(self, MockedSettings): + # GIVEN: A slide controller, actions needed, settins set to False. + slide_controller = SlideController(None) + mocked_settings = MagicMock() + mocked_settings.value.return_value = False + MockedSettings.return_value = mocked_settings + slide_controller.service_item = MagicMock() + slide_controller.service_item.is_media = MagicMock() + slide_controller.on_media_close = MagicMock() + slide_controller.on_go_live = MagicMock() + slide_controller.on_preview_add_to_service = MagicMock() + slide_controller.media_reset = MagicMock() + Registry.create() + Registry().set_flag('has doubleclick added item to service', False) + + # WHEN: on_preview_double_click is called + slide_controller.on_preview_double_click() + + # THEN: The call to addActions should be correct + self.assertEqual(0, slide_controller.on_go_live.call_count, 'on_go_live Should have not been called.') + self.assertEqual(1, slide_controller.on_preview_add_to_service.call_count, 'Should have been called once.') + @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') @patch(u'PyQt5.QtCore.QTimer.singleShot') def test_update_preview_live(self, mocked_singleShot, mocked_image_manager):