Merge branch 'master' of gitlab.com:openlp/openlp

This commit is contained in:
Tim 2020-12-21 14:15:16 +00:00
commit 7698c5da8c
No known key found for this signature in database
GPG Key ID: 3D454289AF831A6D
16 changed files with 659 additions and 480 deletions

View File

@ -4,23 +4,23 @@ cache:
- '%LOCALAPPDATA%\pip\Cache' - '%LOCALAPPDATA%\pip\Cache'
- /Users/appveyor/Libraries/Caches/pip - /Users/appveyor/Libraries/Caches/pip
stack: python 3.9 stack: python 3.8
environment: environment:
matrix: matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
PY_DIR: C:\\Python39-x64 PY_DIR: C:\\Python39-x64
CHOCO_VLC_ARG: CHOCO_VLC_ARG:
FORCE_PACKAGING: 1 FORCE_PACKAGING: 0
FORCE_PACKAGING_MANUAL: 0 FORCE_PACKAGING_MANUAL: 0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
PY_DIR: C:\\Python39 PY_DIR: C:\\Python39
CHOCO_VLC_ARG: --forcex86 CHOCO_VLC_ARG: --forcex86
FORCE_PACKAGING: 1 FORCE_PACKAGING: 0
FORCE_PACKAGING_MANUAL: 0 FORCE_PACKAGING_MANUAL: 0
- APPVEYOR_BUILD_WORKER_IMAGE: macos-mojave - APPVEYOR_BUILD_WORKER_IMAGE: macos-mojave
QT_QPA_PLATFORM: offscreen QT_QPA_PLATFORM: offscreen
FORCE_PACKAGING: 1 FORCE_PACKAGING: 0
FORCE_PACKAGING_MANUAL: 0 FORCE_PACKAGING_MANUAL: 0
init: init:
@ -30,11 +30,11 @@ install:
# Update pip # Update pip
- python -m pip install --upgrade pip - python -m pip install --upgrade pip
# Install generic dependencies from pypi # Install generic dependencies from pypi
- python -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python pytest mock psycopg2-binary websockets asyncio waitress six webob requests QtAwesome PyQt5 PyQtWebEngine pymediainfo PyMuPDF QDarkStyle python-vlc Pyro4 zeroconf flask-cors pytest-qt pyenchant pysword - python -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python pytest mock psycopg2-binary websockets asyncio waitress six webob requests QtAwesome PyQt5 PyQtWebEngine pymediainfo PyMuPDF QDarkStyle python-vlc zeroconf flask-cors pytest-qt pyenchant pysword
# Install Windows only dependencies # Install Windows only dependencies
- cmd: python -m pip install pyodbc pypiwin32 - cmd: python -m pip install pyodbc pypiwin32
# Mac only dependencies # Mac only dependencies
- sh: python -m pip install pyobjc-core pyobjc-framework-Cocoa py-applescript - sh: python -m pip install Pyro4 pyobjc-core pyobjc-framework-Cocoa py-applescript
build: off build: off
@ -77,6 +77,7 @@ after_test:
# install dmgbuild tool # install dmgbuild tool
python -m pip install --no-warn-script-location dmgbuild python -m pip install --no-warn-script-location dmgbuild
# use brew to build enchant, needed for pyenchant # use brew to build enchant, needed for pyenchant
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
brew update --quiet brew update --quiet
brew install enchant brew install enchant
} }

View File

@ -1 +1 @@
2.9.1 2.9.2

View File

@ -406,5 +406,5 @@ class ScreenList(metaclass=Singleton):
The primary screen has changed, let's sort it out and then notify everyone The primary screen has changed, let's sort it out and then notify everyone
""" """
for screen in self.screens: for screen in self.screens:
screen.is_primary = self.desktop.primaryScreen().geometry() == screen.geometry screen.is_primary = self.application.primaryScreen().geometry() == screen.geometry
Registry().execute('config_screen_changed') Registry().execute('config_screen_changed')

View File

@ -22,16 +22,13 @@
The :mod:`advancedtab` provides an advanced settings facility. The :mod:`advancedtab` provides an advanced settings facility.
""" """
import logging import logging
from datetime import datetime, timedelta
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtWidgets
from openlp.core.common import SlideLimits, is_win
from openlp.core.common.applocation import AppLocation from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, format_time, translate from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib.settingstab import SettingsTab from openlp.core.lib.settingstab import SettingsTab
from openlp.core.ui.icons import UiIcons from openlp.core.ui.icons import UiIcons
from openlp.core.ui.style import HAS_DARK_STYLE
from openlp.core.widgets.edits import PathEdit from openlp.core.widgets.edits import PathEdit
from openlp.core.widgets.enums import PathEditType from openlp.core.widgets.enums import PathEditType
from openlp.core.widgets.widgets import ProxyWidget from openlp.core.widgets.widgets import ProxyWidget
@ -51,10 +48,6 @@ class AdvancedTab(SettingsTab):
""" """
self.data_exists = False self.data_exists = False
self.icon_path = UiIcons().settings self.icon_path = UiIcons().settings
self.autoscroll_map = [None, {'dist': -1, 'pos': 0}, {'dist': -1, 'pos': 1}, {'dist': -1, 'pos': 2},
{'dist': 0, 'pos': 0}, {'dist': 0, 'pos': 1}, {'dist': 0, 'pos': 2},
{'dist': 0, 'pos': 3}, {'dist': 1, 'pos': 0}, {'dist': 1, 'pos': 1},
{'dist': 1, 'pos': 2}, {'dist': 1, 'pos': 3}]
advanced_translated = translate('OpenLP.AdvancedTab', 'Advanced') advanced_translated = translate('OpenLP.AdvancedTab', 'Advanced')
super(AdvancedTab, self).__init__(parent, 'Advanced', advanced_translated) super(AdvancedTab, self).__init__(parent, 'Advanced', advanced_translated)
@ -64,80 +57,6 @@ class AdvancedTab(SettingsTab):
""" """
self.setObjectName('AdvancedTab') self.setObjectName('AdvancedTab')
super(AdvancedTab, self).setup_ui() super(AdvancedTab, self).setup_ui()
self.ui_group_box = QtWidgets.QGroupBox(self.left_column)
self.ui_group_box.setObjectName('ui_group_box')
self.ui_layout = QtWidgets.QFormLayout(self.ui_group_box)
self.ui_layout.setObjectName('ui_layout')
self.recent_label = QtWidgets.QLabel(self.ui_group_box)
self.recent_label.setObjectName('recent_label')
self.recent_spin_box = QtWidgets.QSpinBox(self.ui_group_box)
self.recent_spin_box.setObjectName('recent_spin_box')
self.recent_spin_box.setMinimum(0)
self.ui_layout.addRow(self.recent_label, self.recent_spin_box)
self.media_plugin_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.media_plugin_check_box.setObjectName('media_plugin_check_box')
self.ui_layout.addRow(self.media_plugin_check_box)
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
self.ui_layout.addRow(self.hide_mouse_check_box)
self.double_click_live_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.double_click_live_check_box.setObjectName('double_click_live_check_box')
self.ui_layout.addRow(self.double_click_live_check_box)
self.single_click_preview_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.single_click_preview_check_box.setObjectName('single_click_preview_check_box')
self.ui_layout.addRow(self.single_click_preview_check_box)
self.single_click_service_preview_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.single_click_service_preview_check_box.setObjectName('single_click_service_preview_check_box')
self.ui_layout.addRow(self.single_click_service_preview_check_box)
self.expand_service_item_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.expand_service_item_check_box.setObjectName('expand_service_item_check_box')
self.ui_layout.addRow(self.expand_service_item_check_box)
self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box)
self.slide_max_height_label.setObjectName('slide_max_height_label')
self.slide_max_height_combo_box = QtWidgets.QComboBox(self.ui_group_box)
self.slide_max_height_combo_box.addItem('', userData=0)
self.slide_max_height_combo_box.addItem('', userData=-4)
# Generate numeric values for combo box dynamically
for px in range(60, 801, 5):
self.slide_max_height_combo_box.addItem(str(px) + 'px', userData=px)
self.slide_max_height_combo_box.setObjectName('slide_max_height_combo_box')
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_combo_box)
self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box)
self.autoscroll_label.setObjectName('autoscroll_label')
self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box)
self.autoscroll_combo_box.addItems(['', '', '', '', '', '', '', '', '', '', '', ''])
self.autoscroll_combo_box.setObjectName('autoscroll_combo_box')
self.ui_layout.addRow(self.autoscroll_label)
self.ui_layout.addRow(self.autoscroll_combo_box)
self.search_as_type_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
self.ui_layout.addRow(self.search_as_type_check_box)
self.enable_auto_close_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
self.ui_layout.addRow(self.enable_auto_close_check_box)
self.left_layout.addWidget(self.ui_group_box)
if not is_win() and HAS_DARK_STYLE:
self.use_dark_style_checkbox = QtWidgets.QCheckBox(self.ui_group_box)
self.use_dark_style_checkbox.setObjectName('use_dark_style_checkbox')
self.ui_layout.addRow(self.use_dark_style_checkbox)
# Service Item Slide Limits
self.slide_group_box = QtWidgets.QGroupBox(self.left_column)
self.slide_group_box.setObjectName('slide_group_box')
self.slide_layout = QtWidgets.QVBoxLayout(self.slide_group_box)
self.slide_layout.setObjectName('slide_layout')
self.slide_label = QtWidgets.QLabel(self.slide_group_box)
self.slide_label.setWordWrap(True)
self.slide_layout.addWidget(self.slide_label)
self.end_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
self.end_slide_radio_button.setObjectName('end_slide_radio_button')
self.slide_layout.addWidget(self.end_slide_radio_button)
self.wrap_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
self.wrap_slide_radio_button.setObjectName('wrap_slide_radio_button')
self.slide_layout.addWidget(self.wrap_slide_radio_button)
self.next_item_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
self.next_item_radio_button.setObjectName('next_item_radio_button')
self.slide_layout.addWidget(self.next_item_radio_button)
self.left_layout.addWidget(self.slide_group_box)
# Data Directory # Data Directory
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column) self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
self.data_directory_group_box.setObjectName('data_directory_group_box') self.data_directory_group_box.setObjectName('data_directory_group_box')
@ -165,7 +84,7 @@ class AdvancedTab(SettingsTab):
self.data_directory_layout.addRow(self.new_data_directory_has_files_label) self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
self.left_layout.addWidget(self.data_directory_group_box) self.left_layout.addWidget(self.data_directory_group_box)
# Display Workarounds # Display Workarounds
self.display_workaround_group_box = QtWidgets.QGroupBox(self.right_column) self.display_workaround_group_box = QtWidgets.QGroupBox(self.left_column)
self.display_workaround_group_box.setObjectName('display_workaround_group_box') self.display_workaround_group_box.setObjectName('display_workaround_group_box')
self.display_workaround_layout = QtWidgets.QVBoxLayout(self.display_workaround_group_box) self.display_workaround_layout = QtWidgets.QVBoxLayout(self.display_workaround_group_box)
self.display_workaround_layout.setObjectName('display_workaround_layout') self.display_workaround_layout.setObjectName('display_workaround_layout')
@ -181,46 +100,7 @@ class AdvancedTab(SettingsTab):
self.allow_transparent_display_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box) self.allow_transparent_display_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
self.allow_transparent_display_check_box.setObjectName('allow_transparent_display_check_box') self.allow_transparent_display_check_box.setObjectName('allow_transparent_display_check_box')
self.display_workaround_layout.addWidget(self.allow_transparent_display_check_box) self.display_workaround_layout.addWidget(self.allow_transparent_display_check_box)
self.right_layout.addWidget(self.display_workaround_group_box) self.left_layout.addWidget(self.display_workaround_group_box)
# Default service name
self.service_name_group_box = QtWidgets.QGroupBox(self.right_column)
self.service_name_group_box.setObjectName('service_name_group_box')
self.service_name_layout = QtWidgets.QFormLayout(self.service_name_group_box)
self.service_name_check_box = QtWidgets.QCheckBox(self.service_name_group_box)
self.service_name_check_box.setObjectName('service_name_check_box')
self.service_name_layout.setObjectName('service_name_layout')
self.service_name_layout.addRow(self.service_name_check_box)
self.service_name_time_label = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_time_label.setObjectName('service_name_time_label')
self.service_name_day = QtWidgets.QComboBox(self.service_name_group_box)
self.service_name_day.addItems(['', '', '', '', '', '', '', ''])
self.service_name_day.setObjectName('service_name_day')
self.service_name_time = QtWidgets.QTimeEdit(self.service_name_group_box)
self.service_name_time.setObjectName('service_name_time')
self.service_name_time_layout = QtWidgets.QHBoxLayout()
self.service_name_time_layout.setObjectName('service_name_time_layout')
self.service_name_time_layout.addWidget(self.service_name_day)
self.service_name_time_layout.addWidget(self.service_name_time)
self.service_name_layout.addRow(self.service_name_time_label, self.service_name_time_layout)
self.service_name_label = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_label.setObjectName('service_name_label')
self.service_name_edit = QtWidgets.QLineEdit(self.service_name_group_box)
self.service_name_edit.setObjectName('service_name_edit')
self.service_name_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^/\\?*|<>\[\]":+]+'), self))
self.service_name_revert_button = QtWidgets.QToolButton(self.service_name_group_box)
self.service_name_revert_button.setObjectName('service_name_revert_button')
self.service_name_revert_button.setIcon(UiIcons().undo)
self.service_name_button_layout = QtWidgets.QHBoxLayout()
self.service_name_button_layout.setObjectName('service_name_button_layout')
self.service_name_button_layout.addWidget(self.service_name_edit)
self.service_name_button_layout.addWidget(self.service_name_revert_button)
self.service_name_layout.addRow(self.service_name_label, self.service_name_button_layout)
self.service_name_example_label = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_example_label.setObjectName('service_name_example_label')
self.service_name_example = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_example.setObjectName('service_name_example')
self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
self.right_layout.addWidget(self.service_name_group_box)
# Proxies # Proxies
self.proxy_widget = ProxyWidget(self.right_column) self.proxy_widget = ProxyWidget(self.right_column)
self.right_layout.addWidget(self.proxy_widget) self.right_layout.addWidget(self.proxy_widget)
@ -228,91 +108,17 @@ class AdvancedTab(SettingsTab):
self.left_layout.addStretch() self.left_layout.addStretch()
self.right_layout.addStretch() self.right_layout.addStretch()
# Set up all the connections and things # Set up all the connections and things
self.should_update_service_name_example = False
self.service_name_check_box.toggled.connect(self.service_name_check_box_toggled)
self.service_name_day.currentIndexChanged.connect(self.on_service_name_day_changed)
self.service_name_time.timeChanged.connect(self.update_service_name_example)
self.service_name_edit.textChanged.connect(self.update_service_name_example)
self.service_name_revert_button.clicked.connect(self.on_service_name_revert_button_clicked)
self.alternate_rows_check_box.toggled.connect(self.on_alternate_rows_check_box_toggled) self.alternate_rows_check_box.toggled.connect(self.on_alternate_rows_check_box_toggled)
self.data_directory_path_edit.pathChanged.connect(self.on_data_directory_path_edit_path_changed) self.data_directory_path_edit.pathChanged.connect(self.on_data_directory_path_edit_path_changed)
self.data_directory_cancel_button.clicked.connect(self.on_data_directory_cancel_button_clicked) self.data_directory_cancel_button.clicked.connect(self.on_data_directory_cancel_button_clicked)
self.data_directory_copy_check_box.toggled.connect(self.on_data_directory_copy_check_box_toggled) self.data_directory_copy_check_box.toggled.connect(self.on_data_directory_copy_check_box_toggled)
self.end_slide_radio_button.clicked.connect(self.on_end_slide_button_clicked)
self.wrap_slide_radio_button.clicked.connect(self.on_wrap_slide_button_clicked)
self.next_item_radio_button.clicked.connect(self.on_next_item_button_clicked)
self.search_as_type_check_box.stateChanged.connect(self.on_search_as_type_check_box_changed)
def retranslate_ui(self): def retranslate_ui(self):
""" """
Setup the interface translation strings. Setup the interface translation strings.
""" """
self.tab_title_visible = UiStrings().Advanced self.tab_title_visible = UiStrings().Advanced
self.ui_group_box.setTitle(translate('OpenLP.AdvancedTab', 'UI Settings'))
self.data_directory_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Data Location')) 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 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',
'Preview items when clicked in Library'))
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'))
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'))
self.slide_max_height_combo_box.setItemText(1, translate('OpenLP.AdvancedTab', 'Automatic'))
self.autoscroll_label.setText(translate('OpenLP.AdvancedTab',
'When changing slides:'))
self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll'))
self.autoscroll_combo_box.setItemText(1, translate('OpenLP.AdvancedTab',
'Auto-scroll the previous slide into view'))
self.autoscroll_combo_box.setItemText(2, translate('OpenLP.AdvancedTab',
'Auto-scroll the previous slide to top'))
self.autoscroll_combo_box.setItemText(3, translate('OpenLP.AdvancedTab',
'Auto-scroll the previous slide to middle'))
self.autoscroll_combo_box.setItemText(4, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide into view'))
self.autoscroll_combo_box.setItemText(5, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide to top'))
self.autoscroll_combo_box.setItemText(6, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide to middle'))
self.autoscroll_combo_box.setItemText(7, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide to bottom'))
self.autoscroll_combo_box.setItemText(8, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide into view'))
self.autoscroll_combo_box.setItemText(9, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide to top'))
self.autoscroll_combo_box.setItemText(10, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide to middle'))
self.autoscroll_combo_box.setItemText(11, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide to bottom'))
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
'Enable application exit confirmation'))
if not is_win() and HAS_DARK_STYLE:
self.use_dark_style_checkbox.setText(translate('OpenLP.AdvancedTab', 'Use dark style (needs restart)'))
self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
self.service_name_check_box.setText(translate('OpenLP.AdvancedTab', 'Enable default service name'))
self.service_name_time_label.setText(translate('OpenLP.AdvancedTab', 'Date and Time:'))
self.service_name_day.setItemText(0, translate('OpenLP.AdvancedTab', 'Monday'))
self.service_name_day.setItemText(1, translate('OpenLP.AdvancedTab', 'Tuesday'))
self.service_name_day.setItemText(2, translate('OpenLP.AdvancedTab', 'Wednesday'))
self.service_name_day.setItemText(3, translate('OpenLP.AdvancedTab', 'Thursday'))
self.service_name_day.setItemText(4, translate('OpenLP.AdvancedTab', 'Friday'))
self.service_name_day.setItemText(5, translate('OpenLP.AdvancedTab', 'Saturday'))
self.service_name_day.setItemText(6, translate('OpenLP.AdvancedTab', 'Sunday'))
self.service_name_day.setItemText(7, translate('OpenLP.AdvancedTab', 'Now'))
self.service_name_time.setToolTip(translate('OpenLP.AdvancedTab', 'Time when usual service starts.'))
self.service_name_label.setText(translate('OpenLP.AdvancedTab', 'Name:'))
self.service_name_edit.setToolTip(translate('OpenLP.AdvancedTab', 'Consult the OpenLP manual for usage.'))
self.service_name_revert_button.setToolTip(
translate('OpenLP.AdvancedTab',
'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName))
self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Path:')) self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Path:'))
self.data_directory_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel')) self.data_directory_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel'))
self.data_directory_cancel_button.setToolTip( self.data_directory_cancel_button.setToolTip(
@ -329,67 +135,19 @@ class AdvancedTab(SettingsTab):
self.alternate_rows_check_box.setText(translate('OpenLP.AdvancedTab', 'Use alternating row colours in lists')) self.alternate_rows_check_box.setText(translate('OpenLP.AdvancedTab', 'Use alternating row colours in lists'))
self.allow_transparent_display_check_box.setText( self.allow_transparent_display_check_box.setText(
translate('OpenLP.AdvancedTab', 'Disable display transparency')) translate('OpenLP.AdvancedTab', 'Disable display transparency'))
# Slide Limits
self.slide_group_box.setTitle(translate('OpenLP.GeneralTab', 'Service Item Slide Limits'))
self.slide_label.setText(translate('OpenLP.GeneralTab', 'Behavior of next/previous on the last/first slide:'))
self.end_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Remain on Slide'))
self.wrap_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Wrap around'))
self.next_item_radio_button.setText(translate('OpenLP.GeneralTab', '&Move to next/previous service item'))
self.search_as_type_check_box.setText(translate('SongsPlugin.GeneralTab', 'Enable search as you type'))
self.proxy_widget.retranslate_ui() self.proxy_widget.retranslate_ui()
def load(self): def load(self):
""" """
Load settings from disk. Load settings from disk.
""" """
# The max recent files value does not have an interface and so never
# gets actually stored in the settings therefore the default value of
# 20 will always be used.
self.recent_spin_box.setMaximum(self.settings.value('advanced/max recent files'))
self.recent_spin_box.setValue(self.settings.value('advanced/recent file count'))
self.media_plugin_check_box.setChecked(self.settings.value('advanced/save current plugin'))
self.double_click_live_check_box.setChecked(self.settings.value('advanced/double click live'))
self.single_click_preview_check_box.setChecked(self.settings.value('advanced/single click preview'))
self.single_click_service_preview_check_box.setChecked(
self.settings.value('advanced/single click service preview'))
self.expand_service_item_check_box.setChecked(self.settings.value('advanced/expand service item'))
slide_max_height_value = self.settings.value('advanced/slide max height')
for i in range(0, self.slide_max_height_combo_box.count()):
if self.slide_max_height_combo_box.itemData(i) == slide_max_height_value:
self.slide_max_height_combo_box.setCurrentIndex(i)
autoscroll_value = self.settings.value('advanced/autoscrolling')
for i in range(0, len(self.autoscroll_map)):
if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
self.autoscroll_combo_box.setCurrentIndex(i)
self.enable_auto_close_check_box.setChecked(self.settings.value('advanced/enable exit confirmation'))
if not is_win() and HAS_DARK_STYLE:
self.use_dark_style_checkbox.setChecked(self.settings.value('advanced/use_dark_style'))
self.hide_mouse_check_box.setChecked(self.settings.value('advanced/hide mouse'))
self.service_name_day.setCurrentIndex(self.settings.value('advanced/default service day'))
self.service_name_time.setTime(QtCore.QTime(self.settings.value('advanced/default service hour'),
self.settings.value('advanced/default service minute')))
self.should_update_service_name_example = True
self.service_name_edit.setText(self.settings.value('advanced/default service name'))
default_service_enabled = self.settings.value('advanced/default service enabled')
self.service_name_check_box.setChecked(default_service_enabled)
self.service_name_check_box_toggled(default_service_enabled)
self.ignore_aspect_ratio_check_box.setChecked(self.settings.value('advanced/ignore aspect ratio')) self.ignore_aspect_ratio_check_box.setChecked(self.settings.value('advanced/ignore aspect ratio'))
self.x11_bypass_check_box.setChecked(self.settings.value('advanced/x11 bypass wm')) self.x11_bypass_check_box.setChecked(self.settings.value('advanced/x11 bypass wm'))
self.slide_limits = self.settings.value('advanced/slide limits')
self.is_search_as_you_type_enabled = self.settings.value('advanced/search as type')
self.search_as_type_check_box.setChecked(self.is_search_as_you_type_enabled)
# Prevent the dialog displayed by the alternate_rows_check_box to display. # Prevent the dialog displayed by the alternate_rows_check_box to display.
self.alternate_rows_check_box.blockSignals(True) self.alternate_rows_check_box.blockSignals(True)
self.alternate_rows_check_box.setChecked(self.settings.value('advanced/alternate rows')) self.alternate_rows_check_box.setChecked(self.settings.value('advanced/alternate rows'))
self.alternate_rows_check_box.blockSignals(False) self.alternate_rows_check_box.blockSignals(False)
self.allow_transparent_display_check_box.setChecked(self.settings.value('advanced/disable transparent display')) self.allow_transparent_display_check_box.setChecked(self.settings.value('advanced/disable transparent display'))
if self.slide_limits == SlideLimits.End:
self.end_slide_radio_button.setChecked(True)
elif self.slide_limits == SlideLimits.Wrap:
self.wrap_slide_radio_button.setChecked(True)
else:
self.next_item_radio_button.setChecked(True)
self.data_directory_copy_check_box.hide() self.data_directory_copy_check_box.hide()
self.new_data_directory_has_files_label.hide() self.new_data_directory_has_files_label.hide()
self.data_directory_cancel_button.hide() self.data_directory_cancel_button.hide()
@ -403,49 +161,15 @@ class AdvancedTab(SettingsTab):
""" """
Save settings to disk. Save settings to disk.
""" """
self.settings.setValue('advanced/default service enabled', self.service_name_check_box.isChecked())
service_name = self.service_name_edit.text()
preset_is_valid = self.generate_service_name_example()[0]
if service_name == UiStrings().DefaultServiceName or not preset_is_valid:
self.settings.remove('advanced/default service name')
self.service_name_edit.setText(service_name)
else:
self.settings.setValue('advanced/default service name', service_name)
self.settings.setValue('advanced/default service day', self.service_name_day.currentIndex())
self.settings.setValue('advanced/default service hour', self.service_name_time.time().hour())
self.settings.setValue('advanced/default service minute', self.service_name_time.time().minute())
self.settings.setValue('advanced/recent file count', self.recent_spin_box.value())
self.settings.setValue('advanced/save current plugin', self.media_plugin_check_box.isChecked())
self.settings.setValue('advanced/double click live', self.double_click_live_check_box.isChecked())
self.settings.setValue('advanced/single click preview', self.single_click_preview_check_box.isChecked())
self.settings.setValue('advanced/single click service preview',
self.single_click_service_preview_check_box.isChecked())
self.settings.setValue('advanced/expand service item', self.expand_service_item_check_box.isChecked())
slide_max_height_index = self.slide_max_height_combo_box.currentIndex()
slide_max_height_value = self.slide_max_height_combo_box.itemData(slide_max_height_index)
self.settings.setValue('advanced/slide max height', slide_max_height_value)
self.settings.setValue('advanced/autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()])
self.settings.setValue('advanced/enable exit confirmation', self.enable_auto_close_check_box.isChecked())
self.settings.setValue('advanced/hide mouse', self.hide_mouse_check_box.isChecked())
self.settings.setValue('advanced/alternate rows', self.alternate_rows_check_box.isChecked())
self.settings.setValue('advanced/disable transparent display', self.settings.setValue('advanced/disable transparent display',
self.allow_transparent_display_check_box.isChecked()) self.allow_transparent_display_check_box.isChecked())
self.settings.setValue('advanced/slide limits', self.slide_limits)
self.settings.setValue('advanced/ignore aspect ratio', self.ignore_aspect_ratio_check_box.isChecked()) self.settings.setValue('advanced/ignore aspect ratio', self.ignore_aspect_ratio_check_box.isChecked())
if self.x11_bypass_check_box.isChecked() != self.settings.value('advanced/x11 bypass wm'): if self.x11_bypass_check_box.isChecked() != self.settings.value('advanced/x11 bypass wm'):
self.settings.setValue('advanced/x11 bypass wm', self.x11_bypass_check_box.isChecked()) self.settings.setValue('advanced/x11 bypass wm', self.x11_bypass_check_box.isChecked())
self.settings_form.register_post_process('config_screen_changed') self.settings_form.register_post_process('config_screen_changed')
self.settings_form.register_post_process('slidecontroller_update_slide_limits') self.settings.setValue('advanced/alternate rows', self.alternate_rows_check_box.isChecked())
self.settings.setValue('advanced/search as type', self.is_search_as_you_type_enabled)
if not is_win() and HAS_DARK_STYLE:
self.settings.setValue('advanced/use_dark_style', self.use_dark_style_checkbox.isChecked())
self.proxy_widget.save() self.proxy_widget.save()
def on_search_as_type_check_box_changed(self, check_state):
self.is_search_as_you_type_enabled = (check_state == QtCore.Qt.Checked)
self.settings_form.register_post_process('songs_config_updated')
self.settings_form.register_post_process('custom_config_updated')
def cancel(self): def cancel(self):
""" """
Dialogue was cancelled, remove any pending data path change. Dialogue was cancelled, remove any pending data path change.
@ -453,63 +177,6 @@ class AdvancedTab(SettingsTab):
self.on_data_directory_cancel_button_clicked() self.on_data_directory_cancel_button_clicked()
SettingsTab.cancel(self) SettingsTab.cancel(self)
def service_name_check_box_toggled(self, default_service_enabled):
"""
Service Name options changed
"""
self.service_name_day.setEnabled(default_service_enabled)
time_enabled = default_service_enabled and self.service_name_day.currentIndex() != 7
self.service_name_time.setEnabled(time_enabled)
self.service_name_edit.setEnabled(default_service_enabled)
self.service_name_revert_button.setEnabled(default_service_enabled)
def generate_service_name_example(self):
"""
Display an example of the template used
"""
preset_is_valid = True
if self.service_name_day.currentIndex() == 7:
local_time = datetime.now()
else:
now = datetime.now()
day_delta = self.service_name_day.currentIndex() - now.weekday()
if day_delta < 0:
day_delta += 7
time = now + timedelta(days=day_delta)
local_time = time.replace(
hour=self.service_name_time.time().hour(),
minute=self.service_name_time.time().minute()
)
try:
service_name_example = format_time(self.service_name_edit.text(), local_time)
except ValueError:
preset_is_valid = False
service_name_example = translate('OpenLP.AdvancedTab', 'Syntax error.')
return preset_is_valid, service_name_example
def update_service_name_example(self, returned_value):
"""
Update the example service name.
"""
if not self.should_update_service_name_example:
return
name_example = self.generate_service_name_example()[1]
self.service_name_example.setText(name_example)
def on_service_name_day_changed(self, service_day):
"""
React to the day of the service name changing.
"""
self.service_name_time.setEnabled(service_day != 7)
self.update_service_name_example(None)
def on_service_name_revert_button_clicked(self):
"""
Revert to the default service name.
"""
self.service_name_edit.setText(UiStrings().DefaultServiceName)
self.service_name_edit.setFocus()
def on_data_directory_path_edit_path_changed(self, new_path): def on_data_directory_path_edit_path_changed(self, new_path):
""" """
Handle the `editPathChanged` signal of the data_directory_path_edit Handle the `editPathChanged` signal of the data_directory_path_edit
@ -597,21 +264,3 @@ class AdvancedTab(SettingsTab):
translate('OpenLP.AdvancedTab', translate('OpenLP.AdvancedTab',
'This change will only take effect once OpenLP ' 'This change will only take effect once OpenLP '
'has been restarted.')) 'has been restarted.'))
def on_end_slide_button_clicked(self):
"""
Stop at the end either top ot bottom
"""
self.slide_limits = SlideLimits.End
def on_wrap_slide_button_clicked(self):
"""
Wrap round the service item
"""
self.slide_limits = SlideLimits.Wrap
def on_next_item_button_clicked(self):
"""
Advance to the next service item
"""
self.slide_limits = SlideLimits.Next

View File

@ -24,12 +24,12 @@ The general tab of the configuration dialog.
import logging import logging
from pathlib import Path from pathlib import Path
from PyQt5 import QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import get_images_filter from openlp.core.common import get_images_filter, is_win
from openlp.core.common.i18n import UiStrings, translate from openlp.core.common.i18n import UiStrings, translate
from openlp.core.display.screens import ScreenList
from openlp.core.lib.settingstab import SettingsTab from openlp.core.lib.settingstab import SettingsTab
from openlp.core.ui.style import HAS_DARK_STYLE
from openlp.core.widgets.buttons import ColorButton from openlp.core.widgets.buttons import ColorButton
from openlp.core.widgets.edits import PathEdit from openlp.core.widgets.edits import PathEdit
@ -46,8 +46,11 @@ class GeneralTab(SettingsTab):
Initialise the general settings tab Initialise the general settings tab
""" """
self.logo_background_color = '#ffffff' self.logo_background_color = '#ffffff'
self.screens = ScreenList()
self.icon_path = ':/icon/openlp-logo.svg' self.icon_path = ':/icon/openlp-logo.svg'
self.autoscroll_map = [None, {'dist': -1, 'pos': 0}, {'dist': -1, 'pos': 1}, {'dist': -1, 'pos': 2},
{'dist': 0, 'pos': 0}, {'dist': 0, 'pos': 1}, {'dist': 0, 'pos': 2},
{'dist': 0, 'pos': 3}, {'dist': 1, 'pos': 0}, {'dist': 1, 'pos': 1},
{'dist': 1, 'pos': 2}, {'dist': 1, 'pos': 3}]
general_translated = translate('OpenLP.GeneralTab', 'General') general_translated = translate('OpenLP.GeneralTab', 'General')
super(GeneralTab, self).__init__(parent, 'Core', general_translated) super(GeneralTab, self).__init__(parent, 'Core', general_translated)
@ -58,32 +61,8 @@ class GeneralTab(SettingsTab):
self.setObjectName('GeneralTab') self.setObjectName('GeneralTab')
super(GeneralTab, self).setup_ui() super(GeneralTab, self).setup_ui()
self.tab_layout.setStretch(1, 1) self.tab_layout.setStretch(1, 1)
# CCLI Details
self.ccli_group_box = QtWidgets.QGroupBox(self.left_column)
self.ccli_group_box.setObjectName('ccli_group_box')
self.ccli_layout = QtWidgets.QFormLayout(self.ccli_group_box)
self.ccli_layout.setObjectName('ccli_layout')
self.number_label = QtWidgets.QLabel(self.ccli_group_box)
self.number_label.setObjectName('number_label')
self.number_edit = QtWidgets.QLineEdit(self.ccli_group_box)
self.number_edit.setValidator(QtGui.QIntValidator())
self.number_edit.setObjectName('number_edit')
self.ccli_layout.addRow(self.number_label, self.number_edit)
self.username_label = QtWidgets.QLabel(self.ccli_group_box)
self.username_label.setObjectName('username_label')
self.username_edit = QtWidgets.QLineEdit(self.ccli_group_box)
self.username_edit.setObjectName('username_edit')
self.ccli_layout.addRow(self.username_label, self.username_edit)
self.password_label = QtWidgets.QLabel(self.ccli_group_box)
self.password_label.setObjectName('password_label')
self.password_edit = QtWidgets.QLineEdit(self.ccli_group_box)
self.password_edit.setEchoMode(QtWidgets.QLineEdit.Password)
self.password_edit.setObjectName('password_edit')
self.ccli_layout.addRow(self.password_label, self.password_edit)
self.left_layout.addWidget(self.ccli_group_box)
self.left_layout.addStretch()
# Application Startup # Application Startup
self.startup_group_box = QtWidgets.QGroupBox(self.right_column) self.startup_group_box = QtWidgets.QGroupBox(self.left_column)
self.startup_group_box.setObjectName('startup_group_box') self.startup_group_box.setObjectName('startup_group_box')
self.startup_layout = QtWidgets.QVBoxLayout(self.startup_group_box) self.startup_layout = QtWidgets.QVBoxLayout(self.startup_group_box)
self.startup_layout.setObjectName('startup_layout') self.startup_layout.setObjectName('startup_layout')
@ -99,9 +78,9 @@ class GeneralTab(SettingsTab):
self.check_for_updates_check_box = QtWidgets.QCheckBox(self.startup_group_box) self.check_for_updates_check_box = QtWidgets.QCheckBox(self.startup_group_box)
self.check_for_updates_check_box.setObjectName('check_for_updates_check_box') self.check_for_updates_check_box.setObjectName('check_for_updates_check_box')
self.startup_layout.addWidget(self.check_for_updates_check_box) self.startup_layout.addWidget(self.check_for_updates_check_box)
self.right_layout.addWidget(self.startup_group_box) self.left_layout.addWidget(self.startup_group_box)
# Logo # Logo
self.logo_group_box = QtWidgets.QGroupBox(self.right_column) self.logo_group_box = QtWidgets.QGroupBox(self.left_column)
self.logo_group_box.setObjectName('logo_group_box') self.logo_group_box.setObjectName('logo_group_box')
self.logo_layout = QtWidgets.QFormLayout(self.logo_group_box) self.logo_layout = QtWidgets.QFormLayout(self.logo_group_box)
self.logo_layout.setObjectName('logo_layout') self.logo_layout.setObjectName('logo_layout')
@ -118,78 +97,160 @@ class GeneralTab(SettingsTab):
self.logo_hide_on_startup_check_box = QtWidgets.QCheckBox(self.logo_group_box) self.logo_hide_on_startup_check_box = QtWidgets.QCheckBox(self.logo_group_box)
self.logo_hide_on_startup_check_box.setObjectName('logo_hide_on_startup_check_box') self.logo_hide_on_startup_check_box.setObjectName('logo_hide_on_startup_check_box')
self.logo_layout.addRow(self.logo_hide_on_startup_check_box) self.logo_layout.addRow(self.logo_hide_on_startup_check_box)
self.right_layout.addWidget(self.logo_group_box) self.left_layout.addWidget(self.logo_group_box)
self.logo_color_button.colorChanged.connect(self.on_logo_background_color_changed) self.logo_color_button.colorChanged.connect(self.on_logo_background_color_changed)
# Application Settings # CCLI Details
self.settings_group_box = QtWidgets.QGroupBox(self.right_column) self.ccli_group_box = QtWidgets.QGroupBox(self.left_column)
self.settings_group_box.setObjectName('settings_group_box') self.ccli_group_box.setObjectName('ccli_group_box')
self.settings_layout = QtWidgets.QFormLayout(self.settings_group_box) self.ccli_layout = QtWidgets.QFormLayout(self.ccli_group_box)
self.settings_layout.setObjectName('settings_layout') self.ccli_layout.setObjectName('ccli_layout')
self.auto_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box) self.number_label = QtWidgets.QLabel(self.ccli_group_box)
self.auto_unblank_check_box.setObjectName('auto_unblank_check_box') self.number_label.setObjectName('number_label')
self.settings_layout.addRow(self.auto_unblank_check_box) self.number_edit = QtWidgets.QLineEdit(self.ccli_group_box)
self.click_live_slide_to_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box) self.number_edit.setValidator(QtGui.QIntValidator())
self.click_live_slide_to_unblank_check_box.setObjectName('click_live_slide_to_unblank') self.number_edit.setObjectName('number_edit')
self.settings_layout.addRow(self.click_live_slide_to_unblank_check_box) self.ccli_layout.addRow(self.number_label, self.number_edit)
self.auto_preview_check_box = QtWidgets.QCheckBox(self.settings_group_box) self.left_layout.addWidget(self.ccli_group_box)
self.auto_preview_check_box.setObjectName('auto_preview_check_box') # Ui Settings
self.settings_layout.addRow(self.auto_preview_check_box) self.ui_group_box = QtWidgets.QGroupBox(self.right_column)
# Moved here from image tab self.ui_group_box.setObjectName('ui_group_box')
self.timeout_label = QtWidgets.QLabel(self.settings_group_box) self.ui_layout = QtWidgets.QFormLayout(self.ui_group_box)
self.timeout_label.setObjectName('timeout_label') self.ui_layout.setObjectName('ui_layout')
self.timeout_spin_box = QtWidgets.QSpinBox(self.settings_group_box) self.recent_label = QtWidgets.QLabel(self.ui_group_box)
self.timeout_spin_box.setObjectName('timeout_spin_box') self.recent_label.setObjectName('recent_label')
self.timeout_spin_box.setRange(1, 180) self.recent_spin_box = QtWidgets.QSpinBox(self.ui_group_box)
self.settings_layout.addRow(self.timeout_label, self.timeout_spin_box) self.recent_spin_box.setObjectName('recent_spin_box')
self.right_layout.addWidget(self.settings_group_box) self.recent_spin_box.setMinimum(0)
self.ui_layout.addRow(self.recent_label, self.recent_spin_box)
self.media_plugin_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.media_plugin_check_box.setObjectName('media_plugin_check_box')
self.ui_layout.addRow(self.media_plugin_check_box)
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
self.ui_layout.addRow(self.hide_mouse_check_box)
self.double_click_live_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.double_click_live_check_box.setObjectName('double_click_live_check_box')
self.ui_layout.addRow(self.double_click_live_check_box)
self.single_click_preview_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.single_click_preview_check_box.setObjectName('single_click_preview_check_box')
self.ui_layout.addRow(self.single_click_preview_check_box)
self.single_click_service_preview_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.single_click_service_preview_check_box.setObjectName('single_click_service_preview_check_box')
self.ui_layout.addRow(self.single_click_service_preview_check_box)
self.expand_service_item_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.expand_service_item_check_box.setObjectName('expand_service_item_check_box')
self.ui_layout.addRow(self.expand_service_item_check_box)
self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box)
self.slide_max_height_label.setObjectName('slide_max_height_label')
self.slide_max_height_combo_box = QtWidgets.QComboBox(self.ui_group_box)
self.slide_max_height_combo_box.addItem('', userData=0)
self.slide_max_height_combo_box.addItem('', userData=-4)
# Generate numeric values for combo box dynamically
for px in range(60, 801, 5):
self.slide_max_height_combo_box.addItem(str(px) + 'px', userData=px)
self.slide_max_height_combo_box.setObjectName('slide_max_height_combo_box')
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_combo_box)
self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box)
self.autoscroll_label.setObjectName('autoscroll_label')
self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box)
self.autoscroll_combo_box.addItems(['', '', '', '', '', '', '', '', '', '', '', ''])
self.autoscroll_combo_box.setObjectName('autoscroll_combo_box')
self.ui_layout.addRow(self.autoscroll_label)
self.ui_layout.addRow(self.autoscroll_combo_box)
self.search_as_type_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
self.ui_layout.addRow(self.search_as_type_check_box)
self.enable_auto_close_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
self.ui_layout.addRow(self.enable_auto_close_check_box)
if not is_win() and HAS_DARK_STYLE:
self.use_dark_style_checkbox = QtWidgets.QCheckBox(self.ui_group_box)
self.use_dark_style_checkbox.setObjectName('use_dark_style_checkbox')
self.ui_layout.addRow(self.use_dark_style_checkbox)
self.right_layout.addWidget(self.ui_group_box)
# Push everything in both columns to the top
self.left_layout.addStretch()
self.right_layout.addStretch() self.right_layout.addStretch()
# Remove for now # Connect a few things
self.username_label.setVisible(False) self.search_as_type_check_box.stateChanged.connect(self.on_search_as_type_check_box_changed)
self.username_edit.setVisible(False)
self.password_label.setVisible(False)
self.password_edit.setVisible(False)
def retranslate_ui(self): def retranslate_ui(self):
""" """
Translate the general settings tab to the currently selected language Translate the general settings tab to the currently selected language
""" """
self.tab_title_visible = translate('OpenLP.GeneralTab', 'General') self.tab_title_visible = translate('OpenLP.GeneralTab', 'General')
# Application Startup
self.startup_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Startup')) self.startup_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Startup'))
self.warning_check_box.setText(translate('OpenLP.GeneralTab', 'Show blank screen warning')) self.warning_check_box.setText(translate('OpenLP.GeneralTab', 'Show blank screen warning'))
self.auto_open_check_box.setText(translate('OpenLP.GeneralTab', 'Automatically open the previous service file')) self.auto_open_check_box.setText(translate('OpenLP.GeneralTab', 'Automatically open the previous service file'))
self.show_splash_check_box.setText(translate('OpenLP.GeneralTab', 'Show the splash screen')) self.show_splash_check_box.setText(translate('OpenLP.GeneralTab', 'Show the splash screen'))
# Logo
self.logo_group_box.setTitle(translate('OpenLP.GeneralTab', 'Logo')) self.logo_group_box.setTitle(translate('OpenLP.GeneralTab', 'Logo'))
self.logo_color_label.setText(UiStrings().BackgroundColorColon) self.logo_color_label.setText(UiStrings().BackgroundColorColon)
self.logo_file_label.setText(translate('OpenLP.GeneralTab', 'Logo file:')) self.logo_file_label.setText(translate('OpenLP.GeneralTab', 'Logo file:'))
self.logo_hide_on_startup_check_box.setText(translate('OpenLP.GeneralTab', 'Don\'t show logo on startup')) self.logo_hide_on_startup_check_box.setText(translate('OpenLP.GeneralTab', 'Don\'t show logo on startup'))
self.check_for_updates_check_box.setText(translate('OpenLP.GeneralTab', 'Check for updates to OpenLP')) self.check_for_updates_check_box.setText(translate('OpenLP.GeneralTab', 'Check for updates to OpenLP'))
self.settings_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Settings')) # CCLI Details
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',
'Automatically preview the next item in service'))
self.timeout_label.setText(translate('OpenLP.GeneralTab', 'Timed slide interval:'))
self.timeout_spin_box.setSuffix(translate('OpenLP.GeneralTab', ' sec'))
self.ccli_group_box.setTitle(translate('OpenLP.GeneralTab', 'CCLI Details')) self.ccli_group_box.setTitle(translate('OpenLP.GeneralTab', 'CCLI Details'))
self.number_label.setText(UiStrings().CCLINumberLabel) self.number_label.setText(UiStrings().CCLINumberLabel)
self.username_label.setText(translate('OpenLP.GeneralTab', 'SongSelect username:'))
self.password_label.setText(translate('OpenLP.GeneralTab', 'SongSelect password:'))
self.logo_file_path_edit.dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File') self.logo_file_path_edit.dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File')
self.logo_file_path_edit.dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File') self.logo_file_path_edit.dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File')
self.logo_file_path_edit.filters = '{text};;{names} (*)'.format( self.logo_file_path_edit.filters = '{text};;{names} (*)'.format(
text=get_images_filter(), names=UiStrings().AllFiles) text=get_images_filter(), names=UiStrings().AllFiles)
# UI Settings
self.ui_group_box.setTitle(translate('OpenLP.AdvancedTab', 'UI Settings'))
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 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',
'Preview items when clicked in Library'))
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'))
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'))
self.slide_max_height_combo_box.setItemText(1, translate('OpenLP.AdvancedTab', 'Automatic'))
self.autoscroll_label.setText(translate('OpenLP.AdvancedTab',
'When changing slides:'))
self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll'))
self.autoscroll_combo_box.setItemText(1, translate('OpenLP.AdvancedTab',
'Auto-scroll the previous slide into view'))
self.autoscroll_combo_box.setItemText(2, translate('OpenLP.AdvancedTab',
'Auto-scroll the previous slide to top'))
self.autoscroll_combo_box.setItemText(3, translate('OpenLP.AdvancedTab',
'Auto-scroll the previous slide to middle'))
self.autoscroll_combo_box.setItemText(4, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide into view'))
self.autoscroll_combo_box.setItemText(5, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide to top'))
self.autoscroll_combo_box.setItemText(6, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide to middle'))
self.autoscroll_combo_box.setItemText(7, translate('OpenLP.AdvancedTab',
'Auto-scroll the current slide to bottom'))
self.autoscroll_combo_box.setItemText(8, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide into view'))
self.autoscroll_combo_box.setItemText(9, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide to top'))
self.autoscroll_combo_box.setItemText(10, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide to middle'))
self.autoscroll_combo_box.setItemText(11, translate('OpenLP.AdvancedTab',
'Auto-scroll the next slide to bottom'))
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
'Enable application exit confirmation'))
self.search_as_type_check_box.setText(translate('SongsPlugin.GeneralTab', 'Enable search as you type'))
if not is_win() and HAS_DARK_STYLE:
self.use_dark_style_checkbox.setText(translate('OpenLP.AdvancedTab', 'Use dark style (needs restart)'))
self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
def load(self): def load(self):
""" """
Load the settings to populate the form Load the settings to populate the form
""" """
self.number_edit.setText(self.settings.value('core/ccli number')) self.number_edit.setText(self.settings.value('core/ccli number'))
self.username_edit.setText(self.settings.value('core/songselect username'))
self.password_edit.setText(self.settings.value('core/songselect password'))
self.auto_unblank_check_box.setChecked(self.settings.value('core/auto unblank'))
self.click_live_slide_to_unblank_check_box.setChecked(self.settings.value('core/click live slide to unblank'))
self.warning_check_box.setChecked(self.settings.value('core/blank warning')) self.warning_check_box.setChecked(self.settings.value('core/blank warning'))
self.auto_open_check_box.setChecked(self.settings.value('core/auto open')) self.auto_open_check_box.setChecked(self.settings.value('core/auto open'))
self.show_splash_check_box.setChecked(self.settings.value('core/show splash')) self.show_splash_check_box.setChecked(self.settings.value('core/show splash'))
@ -198,8 +259,32 @@ class GeneralTab(SettingsTab):
self.logo_hide_on_startup_check_box.setChecked(self.settings.value('core/logo hide on startup')) self.logo_hide_on_startup_check_box.setChecked(self.settings.value('core/logo hide on startup'))
self.logo_color_button.color = self.logo_background_color self.logo_color_button.color = self.logo_background_color
self.check_for_updates_check_box.setChecked(self.settings.value('core/update check')) self.check_for_updates_check_box.setChecked(self.settings.value('core/update check'))
self.auto_preview_check_box.setChecked(self.settings.value('core/auto preview')) # UI Settings
self.timeout_spin_box.setValue(self.settings.value('core/loop delay')) # The max recent files value does not have an interface and so never
# gets actually stored in the settings therefore the default value of
# 20 will always be used.
self.recent_spin_box.setMaximum(self.settings.value('advanced/max recent files'))
self.recent_spin_box.setValue(self.settings.value('advanced/recent file count'))
self.media_plugin_check_box.setChecked(self.settings.value('advanced/save current plugin'))
self.double_click_live_check_box.setChecked(self.settings.value('advanced/double click live'))
self.single_click_preview_check_box.setChecked(self.settings.value('advanced/single click preview'))
self.single_click_service_preview_check_box.setChecked(
self.settings.value('advanced/single click service preview'))
self.expand_service_item_check_box.setChecked(self.settings.value('advanced/expand service item'))
slide_max_height_value = self.settings.value('advanced/slide max height')
for i in range(0, self.slide_max_height_combo_box.count()):
if self.slide_max_height_combo_box.itemData(i) == slide_max_height_value:
self.slide_max_height_combo_box.setCurrentIndex(i)
autoscroll_value = self.settings.value('advanced/autoscrolling')
for i in range(0, len(self.autoscroll_map)):
if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
self.autoscroll_combo_box.setCurrentIndex(i)
self.enable_auto_close_check_box.setChecked(self.settings.value('advanced/enable exit confirmation'))
if not is_win() and HAS_DARK_STYLE:
self.use_dark_style_checkbox.setChecked(self.settings.value('advanced/use_dark_style'))
self.hide_mouse_check_box.setChecked(self.settings.value('advanced/hide mouse'))
self.is_search_as_you_type_enabled = self.settings.value('advanced/search as type')
self.search_as_type_check_box.setChecked(self.is_search_as_you_type_enabled)
def save(self): def save(self):
""" """
@ -212,14 +297,24 @@ class GeneralTab(SettingsTab):
self.settings.setValue('core/logo file', self.logo_file_path_edit.path) self.settings.setValue('core/logo file', self.logo_file_path_edit.path)
self.settings.setValue('core/logo hide on startup', self.logo_hide_on_startup_check_box.isChecked()) self.settings.setValue('core/logo hide on startup', self.logo_hide_on_startup_check_box.isChecked())
self.settings.setValue('core/update check', self.check_for_updates_check_box.isChecked()) self.settings.setValue('core/update check', self.check_for_updates_check_box.isChecked())
self.settings.setValue('core/auto unblank', self.auto_unblank_check_box.isChecked())
self.settings.setValue('core/click live slide to unblank',
self.click_live_slide_to_unblank_check_box.isChecked())
self.settings.setValue('core/auto preview', self.auto_preview_check_box.isChecked())
self.settings.setValue('core/loop delay', self.timeout_spin_box.value())
self.settings.setValue('core/ccli number', self.number_edit.displayText()) self.settings.setValue('core/ccli number', self.number_edit.displayText())
self.settings.setValue('core/songselect username', self.username_edit.displayText()) # UI Settings
self.settings.setValue('core/songselect password', self.password_edit.displayText()) self.settings.setValue('advanced/recent file count', self.recent_spin_box.value())
self.settings.setValue('advanced/save current plugin', self.media_plugin_check_box.isChecked())
self.settings.setValue('advanced/double click live', self.double_click_live_check_box.isChecked())
self.settings.setValue('advanced/single click preview', self.single_click_preview_check_box.isChecked())
self.settings.setValue('advanced/single click service preview',
self.single_click_service_preview_check_box.isChecked())
self.settings.setValue('advanced/expand service item', self.expand_service_item_check_box.isChecked())
slide_max_height_index = self.slide_max_height_combo_box.currentIndex()
slide_max_height_value = self.slide_max_height_combo_box.itemData(slide_max_height_index)
self.settings.setValue('advanced/slide max height', slide_max_height_value)
self.settings.setValue('advanced/autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()])
self.settings.setValue('advanced/enable exit confirmation', self.enable_auto_close_check_box.isChecked())
self.settings.setValue('advanced/hide mouse', self.hide_mouse_check_box.isChecked())
self.settings.setValue('advanced/search as type', self.is_search_as_you_type_enabled)
if not is_win() and HAS_DARK_STYLE:
self.settings.setValue('advanced/use_dark_style', self.use_dark_style_checkbox.isChecked())
self.post_set_up() self.post_set_up()
def post_set_up(self): def post_set_up(self):
@ -233,3 +328,8 @@ class GeneralTab(SettingsTab):
Select the background color for logo. Select the background color for logo.
""" """
self.logo_background_color = color self.logo_background_color = color
def on_search_as_type_check_box_changed(self, check_state):
self.is_search_as_you_type_enabled = (check_state == QtCore.Qt.Checked)
self.settings_form.register_post_process('songs_config_updated')
self.settings_form.register_post_process('custom_config_updated')

View File

@ -64,11 +64,12 @@ class MediaTab(SettingsTab):
self.left_layout.addWidget(self.live_media_group_box) self.left_layout.addWidget(self.live_media_group_box)
self.vlc_arguments_group_box = QtWidgets.QGroupBox(self.left_column) self.vlc_arguments_group_box = QtWidgets.QGroupBox(self.left_column)
self.vlc_arguments_group_box.setObjectName('vlc_arguments_group_box') self.vlc_arguments_group_box.setObjectName('vlc_arguments_group_box')
self.vlc_arguments_layout = QtWidgets.QHBoxLayout(self.vlc_arguments_group_box) self.vlc_arguments_layout = QtWidgets.QFormLayout(self.vlc_arguments_group_box)
self.vlc_arguments_layout.setObjectName('vlc_arguments_layout') self.vlc_arguments_layout.setObjectName('vlc_arguments_layout')
self.vlc_arguments_layout.setContentsMargins(0, 0, 0, 0) self.vlc_arguments_label = QtWidgets.QLabel(self.vlc_arguments_group_box)
self.vlc_arguments_label.setObjectName('vlc_arguments_label')
self.vlc_arguments_edit = QtWidgets.QLineEdit(self) self.vlc_arguments_edit = QtWidgets.QLineEdit(self)
self.vlc_arguments_layout.addWidget(self.vlc_arguments_edit) self.vlc_arguments_layout.addRow(self.vlc_arguments_label, self.vlc_arguments_edit)
self.left_layout.addWidget(self.vlc_arguments_group_box) self.left_layout.addWidget(self.vlc_arguments_group_box)
self.left_layout.addStretch() self.left_layout.addStretch()
self.right_layout.addStretch() self.right_layout.addStretch()
@ -80,7 +81,8 @@ class MediaTab(SettingsTab):
Translate the UI on the fly Translate the UI on the fly
""" """
self.live_media_group_box.setTitle(translate('MediaPlugin.MediaTab', 'Live Media')) self.live_media_group_box.setTitle(translate('MediaPlugin.MediaTab', 'Live Media'))
self.vlc_arguments_group_box.setTitle(translate('MediaPlugin.MediaTab', 'VLC arguments (requires restart)')) self.vlc_arguments_group_box.setTitle(translate('MediaPlugin.MediaTab', 'VLC (requires restart)'))
self.vlc_arguments_label.setText(translate('MediaPlugin.MediaTab', 'Extra arguments:'))
self.auto_start_check_box.setText(translate('MediaPlugin.MediaTab', 'Start Live items automatically')) self.auto_start_check_box.setText(translate('MediaPlugin.MediaTab', 'Start Live items automatically'))
def load(self): def load(self):

View File

@ -0,0 +1,326 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2020 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program 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 General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
The services tab of the configuration dialog.
"""
import logging
from datetime import datetime, timedelta
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import SlideLimits
from openlp.core.common.i18n import UiStrings, format_time, translate
from openlp.core.ui.icons import UiIcons
from openlp.core.lib.settingstab import SettingsTab
log = logging.getLogger(__name__)
class ServiceTab(SettingsTab):
"""
ServiceTab is the service settings tab in the settings dialog.
"""
def __init__(self, parent):
"""
Initialise the service settings tab
"""
# self.logo_background_color = '#ffffff'
self.icon_path = UiIcons().live
self.should_update_service_name_example = True
service_translated = translate('OpenLP.ServiceTab', 'Service')
super(ServiceTab, self).__init__(parent, 'Service', service_translated)
def setup_ui(self):
"""
Create the user interface for the service settings tab
"""
self.setObjectName('ServiceTab')
super(ServiceTab, self).setup_ui()
self.tab_layout.setStretch(1, 1)
# Default service name
self.service_name_group_box = QtWidgets.QGroupBox(self.left_column)
self.service_name_group_box.setObjectName('service_name_group_box')
self.service_name_layout = QtWidgets.QFormLayout(self.service_name_group_box)
self.service_name_check_box = QtWidgets.QCheckBox(self.service_name_group_box)
self.service_name_check_box.setObjectName('service_name_check_box')
self.service_name_layout.setObjectName('service_name_layout')
self.service_name_layout.addRow(self.service_name_check_box)
self.service_name_time_label = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_time_label.setObjectName('service_name_time_label')
self.service_name_day = QtWidgets.QComboBox(self.service_name_group_box)
self.service_name_day.addItems(['', '', '', '', '', '', '', ''])
self.service_name_day.setObjectName('service_name_day')
self.service_name_time = QtWidgets.QTimeEdit(self.service_name_group_box)
self.service_name_time.setObjectName('service_name_time')
self.service_name_time_layout = QtWidgets.QHBoxLayout()
self.service_name_time_layout.setObjectName('service_name_time_layout')
self.service_name_time_layout.addWidget(self.service_name_day)
self.service_name_time_layout.addWidget(self.service_name_time)
self.service_name_layout.addRow(self.service_name_time_label, self.service_name_time_layout)
self.service_name_label = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_label.setObjectName('service_name_label')
self.service_name_edit = QtWidgets.QLineEdit(self.service_name_group_box)
self.service_name_edit.setObjectName('service_name_edit')
self.service_name_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^/\\?*|<>\[\]":+]+'), self))
self.service_name_revert_button = QtWidgets.QToolButton(self.service_name_group_box)
self.service_name_revert_button.setObjectName('service_name_revert_button')
self.service_name_revert_button.setIcon(UiIcons().undo)
self.service_name_button_layout = QtWidgets.QHBoxLayout()
self.service_name_button_layout.setObjectName('service_name_button_layout')
self.service_name_button_layout.addWidget(self.service_name_edit)
self.service_name_button_layout.addWidget(self.service_name_revert_button)
self.service_name_layout.addRow(self.service_name_label, self.service_name_button_layout)
self.service_name_example_label = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_example_label.setObjectName('service_name_example_label')
self.service_name_example = QtWidgets.QLabel(self.service_name_group_box)
self.service_name_example.setObjectName('service_name_example')
self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
self.left_layout.addWidget(self.service_name_group_box)
# Slide Controller
self.slide_controller_groupbox = QtWidgets.QGroupBox(self.left_column)
self.slide_controller_groupbox.setObjectName('slide_controller_groupbox')
self.slide_controller_layout = QtWidgets.QFormLayout(self.slide_controller_groupbox)
self.slide_controller_layout.setObjectName('slide_controller_layout')
self.auto_unblank_check_box = QtWidgets.QCheckBox(self.slide_controller_groupbox)
self.auto_unblank_check_box.setObjectName('auto_unblank_check_box')
self.slide_controller_layout.addRow(self.auto_unblank_check_box)
self.click_live_slide_to_unblank_check_box = QtWidgets.QCheckBox(self.slide_controller_groupbox)
self.click_live_slide_to_unblank_check_box.setObjectName('click_live_slide_to_unblank')
self.slide_controller_layout.addRow(self.click_live_slide_to_unblank_check_box)
self.auto_preview_check_box = QtWidgets.QCheckBox(self.slide_controller_groupbox)
self.auto_preview_check_box.setObjectName('auto_preview_check_box')
self.slide_controller_layout.addRow(self.auto_preview_check_box)
self.timeout_label = QtWidgets.QLabel(self.slide_controller_groupbox)
self.timeout_label.setObjectName('timeout_label')
self.timeout_spin_box = QtWidgets.QSpinBox(self.slide_controller_groupbox)
self.timeout_spin_box.setObjectName('timeout_spin_box')
self.timeout_spin_box.setRange(1, 180)
self.slide_controller_layout.addRow(self.timeout_label, self.timeout_spin_box)
self.left_layout.addWidget(self.slide_controller_groupbox)
# Service Item Wrapping
self.slide_group_box = QtWidgets.QGroupBox(self.right_column)
self.slide_group_box.setObjectName('slide_group_box')
self.slide_layout = QtWidgets.QVBoxLayout(self.slide_group_box)
self.slide_layout.setObjectName('slide_layout')
self.slide_label = QtWidgets.QLabel(self.slide_group_box)
self.slide_label.setWordWrap(True)
self.slide_layout.addWidget(self.slide_label)
self.end_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
self.end_slide_radio_button.setObjectName('end_slide_radio_button')
self.slide_layout.addWidget(self.end_slide_radio_button)
self.wrap_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
self.wrap_slide_radio_button.setObjectName('wrap_slide_radio_button')
self.slide_layout.addWidget(self.wrap_slide_radio_button)
self.next_item_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
self.next_item_radio_button.setObjectName('next_item_radio_button')
self.slide_layout.addWidget(self.next_item_radio_button)
self.right_layout.addWidget(self.slide_group_box)
# Push everything in both columns to the top
self.left_layout.addStretch()
self.right_layout.addStretch()
# Connect signals and slots
self.should_update_service_name_example = False
# Default Service Name
self.service_name_check_box.toggled.connect(self.service_name_check_box_toggled)
self.service_name_day.currentIndexChanged.connect(self.on_service_name_day_changed)
self.service_name_time.timeChanged.connect(self.update_service_name_example)
self.service_name_edit.textChanged.connect(self.update_service_name_example)
self.service_name_revert_button.clicked.connect(self.on_service_name_revert_button_clicked)
# Service Item Wrapping
self.end_slide_radio_button.clicked.connect(self.on_end_slide_button_clicked)
self.wrap_slide_radio_button.clicked.connect(self.on_wrap_slide_button_clicked)
self.next_item_radio_button.clicked.connect(self.on_next_item_button_clicked)
def retranslate_ui(self):
"""
Translate the service settings tab to the currently selected language
"""
self.tab_title_visible = translate('OpenLP.ServiceTab', 'Service')
# Default Service Name
self.service_name_group_box.setTitle(translate('OpenLP.ServiceTab', 'Default Service Name'))
self.service_name_check_box.setText(translate('OpenLP.ServiceTab', 'Enable default service name'))
self.service_name_time_label.setText(translate('OpenLP.ServiceTab', 'Date and Time:'))
self.service_name_day.setItemText(0, translate('OpenLP.ServiceTab', 'Monday'))
self.service_name_day.setItemText(1, translate('OpenLP.ServiceTab', 'Tuesday'))
self.service_name_day.setItemText(2, translate('OpenLP.ServiceTab', 'Wednesday'))
self.service_name_day.setItemText(3, translate('OpenLP.ServiceTab', 'Thursday'))
self.service_name_day.setItemText(4, translate('OpenLP.ServiceTab', 'Friday'))
self.service_name_day.setItemText(5, translate('OpenLP.ServiceTab', 'Saturday'))
self.service_name_day.setItemText(6, translate('OpenLP.ServiceTab', 'Sunday'))
self.service_name_day.setItemText(7, translate('OpenLP.ServiceTab', 'Now'))
self.service_name_time.setToolTip(translate('OpenLP.ServiceTab', 'Time service usually starts.'))
self.service_name_label.setText(translate('OpenLP.ServiceTab', 'Name:'))
self.service_name_edit.setToolTip(translate('OpenLP.ServiceTab', 'Consult the OpenLP manual for usage.'))
self.service_name_revert_button.setToolTip(
translate('OpenLP.ServiceTab',
'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName))
self.service_name_example_label.setText(translate('OpenLP.ServiceTab', 'Example:'))
# Slide Controller
self.slide_controller_groupbox.setTitle(translate('OpenLP.ServiceTab', 'Slide Controller'))
self.click_live_slide_to_unblank_check_box.setText(translate('OpenLP.ServiceTab',
'Unblank display when changing slide in Live'))
self.auto_unblank_check_box.setText(translate('OpenLP.ServiceTab', 'Unblank display when sending '
'items to Live'))
self.auto_preview_check_box.setText(translate('OpenLP.ServiceTab',
'Automatically preview the next item in service'))
self.timeout_label.setText(translate('OpenLP.ServiceTab', 'Timed slide interval:'))
self.timeout_spin_box.setSuffix(translate('OpenLP.ServiceTab', ' sec'))
# Service Item Wrapping
self.slide_group_box.setTitle(translate('OpenLP.ServiceTab', 'Service Item Wrapping'))
self.slide_label.setText(translate('OpenLP.ServiceTab', 'Behavior of next/previous on the last/first slide:'))
self.end_slide_radio_button.setText(translate('OpenLP.ServiceTab', '&Remain on Slide'))
self.wrap_slide_radio_button.setText(translate('OpenLP.ServiceTab', '&Wrap around'))
self.next_item_radio_button.setText(translate('OpenLP.ServiceTab', '&Move to next/previous service item'))
def load(self):
"""
Load the settings to populate the form
"""
# Default Service Name
self.service_name_day.setCurrentIndex(self.settings.value('advanced/default service day'))
self.service_name_time.setTime(QtCore.QTime(self.settings.value('advanced/default service hour'),
self.settings.value('advanced/default service minute')))
self.should_update_service_name_example = True
self.service_name_edit.setText(self.settings.value('advanced/default service name'))
default_service_enabled = self.settings.value('advanced/default service enabled')
self.service_name_check_box.setChecked(default_service_enabled)
self.service_name_check_box_toggled(default_service_enabled)
# Slide Controller
self.auto_unblank_check_box.setChecked(self.settings.value('core/auto unblank'))
self.click_live_slide_to_unblank_check_box.setChecked(self.settings.value('core/click live slide to unblank'))
self.auto_preview_check_box.setChecked(self.settings.value('core/auto preview'))
self.timeout_spin_box.setValue(self.settings.value('core/loop delay'))
# Service Item Wrapping
self.slide_limits = self.settings.value('advanced/slide limits')
if self.slide_limits == SlideLimits.End:
self.end_slide_radio_button.setChecked(True)
elif self.slide_limits == SlideLimits.Wrap:
self.wrap_slide_radio_button.setChecked(True)
else:
self.next_item_radio_button.setChecked(True)
def save(self):
"""
Save the settings from the form
"""
# Default Service Name
self.settings.setValue('advanced/default service enabled', self.service_name_check_box.isChecked())
service_name = self.service_name_edit.text()
preset_is_valid = self.generate_service_name_example()[0]
if service_name == UiStrings().DefaultServiceName or not preset_is_valid:
self.settings.remove('advanced/default service name')
self.service_name_edit.setText(service_name)
else:
self.settings.setValue('advanced/default service name', service_name)
self.settings.setValue('advanced/default service day', self.service_name_day.currentIndex())
self.settings.setValue('advanced/default service hour', self.service_name_time.time().hour())
self.settings.setValue('advanced/default service minute', self.service_name_time.time().minute())
# Slide Controller
self.settings.setValue('core/auto unblank', self.auto_unblank_check_box.isChecked())
self.settings.setValue('core/click live slide to unblank',
self.click_live_slide_to_unblank_check_box.isChecked())
self.settings.setValue('core/auto preview', self.auto_preview_check_box.isChecked())
self.settings.setValue('core/loop delay', self.timeout_spin_box.value())
# Service Item Wrapping
self.settings.setValue('advanced/slide limits', self.slide_limits)
self.settings_form.register_post_process('slidecontroller_update_slide_limits')
self.post_set_up()
def post_set_up(self):
"""
Apply settings after the tab has loaded
"""
self.settings_form.register_post_process('slidecontroller_live_spin_delay')
def service_name_check_box_toggled(self, default_service_enabled):
"""
Service Name options changed
"""
self.service_name_day.setEnabled(default_service_enabled)
time_enabled = default_service_enabled and self.service_name_day.currentIndex() != 7
self.service_name_time.setEnabled(time_enabled)
self.service_name_edit.setEnabled(default_service_enabled)
self.service_name_revert_button.setEnabled(default_service_enabled)
def generate_service_name_example(self):
"""
Display an example of the template used
"""
preset_is_valid = True
if self.service_name_day.currentIndex() == 7:
local_time = datetime.now()
else:
now = datetime.now()
day_delta = self.service_name_day.currentIndex() - now.weekday()
if day_delta < 0:
day_delta += 7
time = now + timedelta(days=day_delta)
local_time = time.replace(
hour=self.service_name_time.time().hour(),
minute=self.service_name_time.time().minute()
)
try:
service_name_example = format_time(self.service_name_edit.text(), local_time)
except ValueError:
preset_is_valid = False
service_name_example = translate('OpenLP.ServiceTab', 'Syntax error.')
return preset_is_valid, service_name_example
def update_service_name_example(self, returned_value):
"""
Update the example service name.
"""
if not self.should_update_service_name_example:
return
name_example = self.generate_service_name_example()[1]
self.service_name_example.setText(name_example)
def on_service_name_day_changed(self, service_day):
"""
React to the day of the service name changing.
"""
self.service_name_time.setEnabled(service_day != 7)
self.update_service_name_example(None)
def on_service_name_revert_button_clicked(self):
"""
Revert to the default service name.
"""
self.service_name_edit.setText(UiStrings().DefaultServiceName)
self.service_name_edit.setFocus()
def on_end_slide_button_clicked(self):
"""
Stop at the end either top ot bottom
"""
self.slide_limits = SlideLimits.End
def on_wrap_slide_button_clicked(self):
"""
Wrap round the service item
"""
self.slide_limits = SlideLimits.Wrap
def on_next_item_button_clicked(self):
"""
Advance to the next service item
"""
self.slide_limits = SlideLimits.Next

View File

@ -38,7 +38,7 @@ class Ui_SettingsDialog(object):
""" """
settings_dialog.setObjectName('settings_dialog') settings_dialog.setObjectName('settings_dialog')
settings_dialog.setWindowIcon(UiIcons().main_icon) settings_dialog.setWindowIcon(UiIcons().main_icon)
settings_dialog.resize(920, 625) settings_dialog.resize(900, 500)
self.dialog_layout = QtWidgets.QGridLayout(settings_dialog) self.dialog_layout = QtWidgets.QGridLayout(settings_dialog)
self.dialog_layout.setObjectName('dialog_layout') self.dialog_layout.setObjectName('dialog_layout')
self.dialog_layout.setContentsMargins(8, 8, 8, 8) self.dialog_layout.setContentsMargins(8, 8, 8, 8)

View File

@ -33,6 +33,7 @@ from openlp.core.lib import build_icon
from openlp.core.projectors.tab import ProjectorTab from openlp.core.projectors.tab import ProjectorTab
from openlp.core.ui.advancedtab import AdvancedTab from openlp.core.ui.advancedtab import AdvancedTab
from openlp.core.ui.generaltab import GeneralTab from openlp.core.ui.generaltab import GeneralTab
from openlp.core.ui.servicetab import ServiceTab
from openlp.core.ui.screenstab import ScreensTab from openlp.core.ui.screenstab import ScreensTab
from openlp.core.ui.themestab import ThemesTab from openlp.core.ui.themestab import ThemesTab
from openlp.core.ui.media.mediatab import MediaTab from openlp.core.ui.media.mediatab import MediaTab
@ -58,6 +59,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
self.setup_ui(self) self.setup_ui(self)
self.setting_list_widget.currentRowChanged.connect(self.list_item_changed) self.setting_list_widget.currentRowChanged.connect(self.list_item_changed)
self.general_tab = None self.general_tab = None
self.service_tab = None
self.themes_tab = None self.themes_tab = None
self.player_tab = None self.player_tab = None
self.projector_tab = None self.projector_tab = None
@ -75,6 +77,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
# take at 0 and the rest shuffle up. # take at 0 and the rest shuffle up.
self.stacked_layout.takeAt(0) self.stacked_layout.takeAt(0)
self.insert_tab(self.general_tab) self.insert_tab(self.general_tab)
self.insert_tab(self.service_tab)
self.insert_tab(self.advanced_tab) self.insert_tab(self.advanced_tab)
self.insert_tab(self.screens_tab) self.insert_tab(self.screens_tab)
self.insert_tab(self.themes_tab) self.insert_tab(self.themes_tab)
@ -159,6 +162,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
""" """
try: try:
self.general_tab = GeneralTab(self) self.general_tab = GeneralTab(self)
self.service_tab = ServiceTab(self)
self.themes_tab = ThemesTab(self) self.themes_tab = ThemesTab(self)
self.projector_tab = ProjectorTab(self) self.projector_tab = ProjectorTab(self)
self.advanced_tab = AdvancedTab(self) self.advanced_tab = AdvancedTab(self)

View File

@ -60,9 +60,8 @@ def upgrade_2(session, metadata):
data_path = AppLocation.get_data_path() data_path = AppLocation.get_data_path()
for row in results.fetchall(): for row in results.fetchall():
file_path_json = json.dumps(Path(row.filename), cls=OpenLPJSONEncoder, base_path=data_path) file_path_json = json.dumps(Path(row.filename), cls=OpenLPJSONEncoder, base_path=data_path)
sql = 'UPDATE image_filenames SET file_path = \'{file_path_json}\' WHERE id = {id}'.format( sql = 'UPDATE image_filenames SET file_path = :file_path_json WHERE id = :id'
file_path_json=file_path_json, id=row.id) conn.execute(sql, {'file_path_json': file_path_json, 'id': row.id})
conn.execute(sql)
# Drop old columns # Drop old columns
if metadata.bind.url.get_dialect().name == 'sqlite': if metadata.bind.url.get_dialect().name == 'sqlite':
drop_columns(op, 'image_filenames', ['filename', ]) drop_columns(op, 'image_filenames', ['filename', ])
@ -91,8 +90,8 @@ def upgrade_3(session, metadata):
log.warning('{image} does not exists, so no sha256 hash added.'.format(image=str(file_path))) log.warning('{image} does not exists, so no sha256 hash added.'.format(image=str(file_path)))
# set a fake "hash" to allow for the upgrade to go through. The image will be marked as invalid # set a fake "hash" to allow for the upgrade to go through. The image will be marked as invalid
hash = 'NONE' hash = 'NONE'
sql = 'UPDATE image_filenames SET file_hash = \'{hash}\' WHERE id = {id}'.format(hash=hash, id=row.id) sql = 'UPDATE image_filenames SET file_hash = :hash WHERE id = :id'
conn.execute(sql) conn.execute(sql, {'hash': hash, 'id': row.id})
# rename thumbnail to use file hash # rename thumbnail to use file hash
ext = file_path.suffix.lower() ext = file_path.suffix.lower()
old_thumb = thumb_path / '{name:d}{ext}'.format(name=row.id, ext=ext) old_thumb = thumb_path / '{name:d}{ext}'.format(name=row.id, ext=ext)

View File

@ -121,8 +121,9 @@ class PdfDocument(PresentationDocument):
src_size = page.bound().round() src_size = page.bound().round()
# keep aspect ratio # keep aspect ratio
scale = min(size.width() / src_size.width, size.height() / src_size.height) scale = min(size.width() / src_size.width, size.height() / src_size.height)
m = fitz.Matrix(scale, scale) matrix = fitz.Matrix(scale, scale)
page.getPixmap(m, alpha=False).writeImage(str(temp_dir_path / 'mainslide{:03d}.png'.format(i))) page.getPixmap(matrix=matrix, alpha=False).writeImage(
str(temp_dir_path / 'mainslide{:03d}.png'.format(i)))
pdf.close() pdf.close()
created_files = sorted(temp_dir_path.glob('*')) created_files = sorted(temp_dir_path.glob('*'))
for image_path in created_files: for image_path in created_files:

View File

@ -182,9 +182,8 @@ def upgrade_7(session, metadata):
data_path = AppLocation.get_data_path() data_path = AppLocation.get_data_path()
for row in results.fetchall(): for row in results.fetchall():
file_path_json = json.dumps(Path(row.file_name), cls=OpenLPJSONEncoder, base_path=data_path) file_path_json = json.dumps(Path(row.file_name), cls=OpenLPJSONEncoder, base_path=data_path)
sql = 'UPDATE media_files SET file_path = \'{file_path_json}\' WHERE id = {id}'.format( sql = 'UPDATE media_files SET file_path = :file_path WHERE id = :id'
file_path_json=file_path_json, id=row.id) conn.execute(sql, {'file_path': file_path_json, 'id': row.id})
conn.execute(sql)
# Drop old columns # Drop old columns
if metadata.bind.url.get_dialect().name == 'sqlite': if metadata.bind.url.get_dialect().name == 'sqlite':
drop_columns(op, 'media_files', ['file_name', ]) drop_columns(op, 'media_files', ['file_name', ])

View File

@ -93,6 +93,26 @@ def test_create_screen_list(mocked_screens, settings):
assert screen_list.screens[1].is_primary is False assert screen_list.screens[1].is_primary is False
@patch('openlp.core.display.screens.QtWidgets.QApplication.screens')
def test_screen_list_on_primary_changed(mocked_screens, settings, registry):
"""Test that the screen is correctly updated when a primary screen is changed"""
# GIVEN: Mocked application
mocked_application = MagicMock()
mocked_screen1 = MagicMock(**{'geometry.return_value': QtCore.QRect(0, 0, 1024, 768)})
mocked_screen2 = MagicMock(**{'geometry.return_value': QtCore.QRect(1024, 0, 1024, 768)})
mocked_application.screens.return_value = [mocked_screen1, mocked_screen2]
mocked_application.primaryScreen.return_value = mocked_screen1
screen_list = ScreenList.create(mocked_application)
# WHEN: on_primary_screen_changed() is called
mocked_application.primaryScreen.return_value = mocked_screen2
screen_list.on_primary_screen_changed()
# THEN: The primary screen should have changed
assert screen_list.screens[0].is_primary is False
assert screen_list.screens[1].is_primary is True
def test_screen_from_dict(): def test_screen_from_dict():
"""Test that all the correct attributes are set when creating a screen from a dictionary""" """Test that all the correct attributes are set when creating a screen from a dictionary"""
# GIVEN: A dictionary of values # GIVEN: A dictionary of values

View File

@ -37,20 +37,3 @@ def test_creation(settings):
# THEN: # THEN:
assert "Advanced" == advanced_tab.tab_title, 'The tab title should be Advanced' assert "Advanced" == advanced_tab.tab_title, 'The tab title should be Advanced'
def test_change_search_as_type(settings):
"""
Test that when search as type is changed custom and song configs are updated
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
advanced_tab = AdvancedTab(settings_form)
# WHEN: I change search as type check box
advanced_tab.on_search_as_type_check_box_changed(True)
# THEN: we should have two post save processed to run
assert 2 == len(settings_form.processes), 'Two post save processes should be created'
assert "songs_config_updated" in settings_form.processes, 'The songs plugin should be called'
assert "custom_config_updated" in settings_form.processes, 'The custom plugin should be called'

View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2020 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program 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 General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
Package to test the openlp.core.ui.generaltab package.
"""
from openlp.core.ui.generaltab import GeneralTab
from openlp.core.ui.settingsform import SettingsForm
def test_creation(settings):
"""
Test that General Tab is created.
"""
# GIVEN: A new General Tab
settings_form = SettingsForm(None)
# WHEN: I create an general tab
general_tab = GeneralTab(settings_form)
# THEN:
assert "Core" == general_tab.tab_title, 'The tab title should be Core'
def test_change_search_as_type(settings):
"""
Test that when search as type is changed custom and song configs are updated
"""
# GIVEN: A new General Tab
settings_form = SettingsForm(None)
general_tab = GeneralTab(settings_form)
# WHEN: I change search as type check box
general_tab.on_search_as_type_check_box_changed(True)
# THEN: we should have two post save processed to run
assert 2 == len(settings_form.processes), 'Two post save processes should be created'
assert "songs_config_updated" in settings_form.processes, 'The songs plugin should be called'
assert "custom_config_updated" in settings_form.processes, 'The custom plugin should be called'

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2020 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program 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 General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
Package to test the openlp.core.ui.servicetab package.
"""
from openlp.core.ui.servicetab import ServiceTab
from openlp.core.ui.settingsform import SettingsForm
def test_creation(settings):
"""
Test that Service Tab is created.
"""
# GIVEN: A new Service Tab
settings_form = SettingsForm(None)
# WHEN: I create an service tab
service_tab = ServiceTab(settings_form)
# THEN:
assert "Service" == service_tab.tab_title, 'The tab title should be Service'