HEAD, plus loading screens from settings

This commit is contained in:
Raoul Snyman 2018-09-06 23:43:01 -07:00
commit 67e6806924
268 changed files with 51695 additions and 1501 deletions

View File

@ -1,46 +1,49 @@
*.pyc
*.*~
\#*\#
*eric[1-9]project
*.ropeproject
*.e4*
.komodotools
*.komodoproject
list
openlp.org 2.0.e4*
documentation/build/html
documentation/build/doctrees
*.log*
dist
OpenLP.egg-info
build
resources/innosetup/Output
.pylint.d
*.qm
openlp/core/resources.py.old
*.qm
resources/windows/warnOpenLP.txt
openlp.cfg
.idea
openlp.pro
.kdev4
tests.kdev4
*.nja
*.orig
__pycache__
*.dll
.directory
*.kate-swp
# Git files
.git
.gitignore
# Rejected diff's
*.rej
*.~\?~
.coverage
\#*\#
build
.cache
cover
*.kdev4
.coverage
coverage
.directory
dist
*.dll
documentation/build/doctrees
documentation/build/html
*.e4*
*eric[1-9]project
.git
# Git files
.gitignore
htmlcov
.idea
*.kate-swp
*.kdev4
.kdev4
*.komodoproject
.komodotools
list
*.log*
*.nja
openlp.cfg
openlp/core/resources.py.old
OpenLP.egg-info
openlp.org 2.0.e4*
openlp.pro
openlp-test-projectordb.sqlite
*.orig
output
*.pyc
__pycache__
.pylint.d
.pytest_cache
*.qm
*.rej
# Rejected diff's
resources/innosetup/Output
resources/windows/warnOpenLP.txt
*.ropeproject
tags
output
htmlcov
@ -49,3 +52,4 @@ openlp-test-projectordb.sqlite
package-lock.json
.cache
test
tests.kdev4

View File

@ -115,7 +115,7 @@ def display_thumbnails(request, controller_name, log, dimensions, file_name, sli
height = -1
image = None
if dimensions:
match = re.search('(\d+)x(\d+)', dimensions)
match = re.search(r'(\d+)x(\d+)', dimensions)
if match:
# let's make sure that the dimensions are within reason
width = sorted([10, int(match.group(1)), 1000])[1]

View File

@ -39,7 +39,7 @@ log = logging.getLogger(__name__)
def _route_to_regex(route):
"""
r"""
Convert a route to a regular expression
For example:

View File

@ -22,13 +22,14 @@
"""
The :mod:`~openlp.core.api.tab` module contains the settings tab for the API
"""
from PyQt5 import QtCore, QtGui, QtNetwork, QtWidgets
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import get_local_ip4
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
from openlp.core.ui.icons import UiIcons
ZERO_URL = '0.0.0.0'
@ -38,11 +39,9 @@ class ApiTab(SettingsTab):
RemoteTab is the Remotes settings tab in the settings dialog.
"""
def __init__(self, parent):
self.icon_path = ':/plugins/plugin_remote.png'
self.icon_path = UiIcons().remote
advanced_translated = translate('OpenLP.AdvancedTab', 'Advanced')
super(ApiTab, self).__init__(parent, 'api', advanced_translated)
self.define_main_window_icon()
self.generate_icon()
def setupUi(self):
self.setObjectName('ApiTab')
@ -55,7 +54,7 @@ class ApiTab(SettingsTab):
self.address_label.setObjectName('address_label')
self.address_edit = QtWidgets.QLineEdit(self.server_settings_group_box)
self.address_edit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'),
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'),
self))
self.address_edit.setObjectName('address_edit')
self.server_settings_layout.addRow(self.address_label, self.address_edit)
@ -155,24 +154,6 @@ class ApiTab(SettingsTab):
self.thumbnails_check_box.stateChanged.connect(self.on_thumbnails_check_box_changed)
self.address_edit.textChanged.connect(self.set_urls)
def define_main_window_icon(self):
"""
Define an icon on the main window to show the state of the server
:return:
"""
self.remote_server_icon = QtWidgets.QLabel(self.main_window.status_bar)
size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
size_policy.setHorizontalStretch(0)
size_policy.setVerticalStretch(0)
size_policy.setHeightForWidth(self.remote_server_icon.sizePolicy().hasHeightForWidth())
self.remote_server_icon.setSizePolicy(size_policy)
self.remote_server_icon.setFrameShadow(QtWidgets.QFrame.Plain)
self.remote_server_icon.setLineWidth(1)
self.remote_server_icon.setScaledContents(True)
self.remote_server_icon.setFixedSize(20, 20)
self.remote_server_icon.setObjectName('remote_server_icon')
self.main_window.status_bar.insertPermanentWidget(2, self.remote_server_icon)
def retranslateUi(self):
self.tab_title_visible = translate('RemotePlugin.RemoteTab', 'Remote Interface')
self.server_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Settings'))
@ -259,7 +240,6 @@ class ApiTab(SettingsTab):
Settings().setValue(self.settings_section + '/authentication enabled', self.user_login_group_box.isChecked())
Settings().setValue(self.settings_section + '/user id', self.user_id.text())
Settings().setValue(self.settings_section + '/password', self.password.text())
self.generate_icon()
if self.update_site_group_box.isChecked():
self.settings_form.register_post_process('download_website')
@ -280,19 +260,3 @@ class ApiTab(SettingsTab):
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:
self.thumbnails = True
def generate_icon(self):
"""
Generate icon for main window
"""
self.remote_server_icon.hide()
icon = QtGui.QImage(':/remote/network_server.png')
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
if Settings().value(self.settings_section + '/authentication enabled'):
overlay = QtGui.QImage(':/remote/network_auth.png')
overlay = overlay.scaled(60, 60, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(icon)
painter.drawImage(20, 0, overlay)
painter.end()
self.remote_server_icon.setPixmap(QtGui.QPixmap.fromImage(icon))
self.remote_server_icon.show()

View File

@ -405,6 +405,7 @@ def main(args=None):
if not Settings().value('core/has run wizard'):
if not FirstTimeLanguageForm().exec():
# if cancel then stop processing
server.close_server()
sys.exit()
# i18n Set Language
language = LanguageManager.get_language()

View File

@ -44,7 +44,7 @@ log = logging.getLogger(__name__ + '.__init__')
FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)')
SECOND_CAMEL_REGEX = re.compile('([a-z0-9])([A-Z])')
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]')
CONTROL_CHARS = re.compile(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]')
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]')
IMAGES_FILTER = None
REPLACMENT_CHARS_MAP = str.maketrans({'\u2018': '\'', '\u2019': '\'', '\u201c': '"', '\u201d': '"', '\u2026': '...',
@ -64,13 +64,17 @@ def get_local_ip4():
log.debug('Getting local IPv4 interface(es) information')
my_ip4 = {}
for iface in QNetworkInterface.allInterfaces():
log.debug('Checking for isValid and flags == IsUP | IsRunning')
if not iface.isValid() or not (iface.flags() & (QNetworkInterface.IsUp | QNetworkInterface.IsRunning)):
continue
log.debug('Checking address(es) protocol')
for address in iface.addressEntries():
ip = address.ip()
# NOTE: Next line will skip if interface is localhost - keep for now until we decide about it later
# if (ip.protocol() == QAbstractSocket.IPv4Protocol) and (ip != QHostAddress.LocalHost):
log.debug('Checking for protocol == IPv4Protocol')
if ip.protocol() == QAbstractSocket.IPv4Protocol:
log.debug('Getting interface information')
my_ip4[iface.name()] = {'ip': ip.toString(),
'broadcast': address.broadcast().toString(),
'netmask': address.netmask().toString(),
@ -79,14 +83,21 @@ def get_local_ip4():
ip.toIPv4Address()).toString()
}
log.debug('Adding {iface} to active list'.format(iface=iface.name()))
if 'localhost' in my_ip4:
log.debug('Renaming windows localhost to lo')
my_ip4['lo'] = my_ip4['localhost']
my_ip4.pop('localhost')
if len(my_ip4) == 0:
log.warning('No active IPv4 network interfaces detected')
if len(my_ip4) == 1:
if 'lo' in my_ip4:
# No active interfaces - so leave localhost in there
log.warning('No active IPv4 interfaces found except localhost')
else:
# Since we have a valid IP4 interface, remove localhost
log.debug('Found at least one IPv4 interface, removing localhost')
my_ip4.pop('lo')
if 'lo' in my_ip4:
log.debug('Found at least one IPv4 interface, removing localhost')
my_ip4.pop('lo')
return my_ip4
@ -471,15 +482,15 @@ def get_file_encoding(file_path):
log.exception('Error detecting file encoding')
def normalize_str(irreg_str):
def normalize_str(irregular_string):
"""
Normalize the supplied string. Remove unicode control chars and tidy up white space.
:param str irreg_str: The string to normalize.
:param str irregular_string: The string to normalize.
:return: The normalized string
:rtype: str
"""
irreg_str = irreg_str.translate(REPLACMENT_CHARS_MAP)
irreg_str = CONTROL_CHARS.sub('', irreg_str)
irreg_str = NEW_LINE_REGEX.sub('\n', irreg_str)
return WHITESPACE_REGEX.sub(' ', irreg_str)
irregular_string = irregular_string.translate(REPLACMENT_CHARS_MAP)
irregular_string = CONTROL_CHARS.sub('', irregular_string)
irregular_string = NEW_LINE_REGEX.sub('\n', irregular_string)
return WHITESPACE_REGEX.sub(' ', irregular_string)

View File

@ -32,6 +32,7 @@ import requests
from openlp.core.common import trace_error_handler
from openlp.core.common.registry import Registry
from openlp.core.common.settings import ProxyMode, Settings
log = logging.getLogger(__name__ + '.__init__')
@ -64,6 +65,39 @@ CONNECTION_TIMEOUT = 30
CONNECTION_RETRIES = 2
def get_proxy_settings(mode=None):
"""
Create a dictionary containing the proxy settings.
:param ProxyMode | None mode: Specify the source of the proxy settings
:return: A dict using the format expected by the requests library.
:rtype: dict | None
"""
settings = Settings()
if mode is None:
mode = settings.value('advanced/proxy mode')
if mode == ProxyMode.NO_PROXY:
return {'http': None, 'https': None}
elif mode == ProxyMode.SYSTEM_PROXY:
# The requests library defaults to using the proxy settings in the environment variables
return
elif mode == ProxyMode.MANUAL_PROXY:
http_addr = settings.value('advanced/proxy http')
https_addr = settings.value('advanced/proxy https')
username = settings.value('advanced/proxy username')
password = settings.value('advanced/proxy password')
basic_auth = ''
if username:
basic_auth = '{username}:{password}@'.format(username=username, password=password)
http_value = None
https_value = None
if http_addr:
http_value = 'http://{basic_auth}{http_addr}'.format(basic_auth=basic_auth, http_addr=http_addr)
if https_addr:
https_value = 'https://{basic_auth}{https_addr}'.format(basic_auth=basic_auth, https_addr=https_addr)
return {'http': http_value, 'https': https_value}
def get_user_agent():
"""
Return a user agent customised for the platform the user is on.
@ -75,14 +109,15 @@ def get_user_agent():
return browser_list[random_index]
def get_web_page(url, headers=None, update_openlp=False, proxies=None):
def get_web_page(url, headers=None, update_openlp=False, proxy=None):
"""
Attempts to download the webpage at url and returns that page or None.
:param url: The URL to be downloaded.
:param header: An optional HTTP header to pass in the request to the web server.
:param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded.
Defaults to False.
:param dict | None headers: An optional HTTP header to pass in the request to the web server.
:param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded. Defaults to False.
:param dict | ProxyMode | None proxy: ProxyMode enum or a dictionary containing the proxy servers, with their types
as the key e.g. {'http': 'http://proxyserver:port', 'https': 'https://proxyserver:port'}
"""
if not url:
return None
@ -90,11 +125,13 @@ def get_web_page(url, headers=None, update_openlp=False, proxies=None):
headers = {}
if 'user-agent' not in [key.lower() for key in headers.keys()]:
headers['User-Agent'] = get_user_agent()
if not isinstance(proxy, dict):
proxy = get_proxy_settings(mode=proxy)
log.debug('Downloading URL = %s' % url)
retries = 0
while retries < CONNECTION_RETRIES:
try:
response = requests.get(url, headers=headers, proxies=proxies, timeout=float(CONNECTION_TIMEOUT))
response = requests.get(url, headers=headers, proxies=proxy, timeout=float(CONNECTION_TIMEOUT))
log.debug('Downloaded page {url}'.format(url=response.url))
break
except OSError:

View File

@ -339,9 +339,10 @@ class UiStrings(object):
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
cls.load(cls)
return cls.__instance__
def __init__(self):
def load(self):
"""
These strings should need a good reason to be retranslated elsewhere.
Should some/more/less of these have an &amp; attached?

View File

@ -206,7 +206,8 @@ def str_to_path(string):
:rtype: openlp.core.common.path.Path | None
"""
if not isinstance(string, str):
raise TypeError('parameter \'string\' must be of type str')
log.error('parameter \'string\' must be of type str, got {} which is a {} instead'.format(string, type(string)))
return None
if string == '':
return None
return Path(string)

View File

@ -58,6 +58,7 @@ class Registry(object):
registry.working_flags = {}
# Allow the tests to remove Registry entries but not the live system
registry.running_under_test = 'nose' in sys.argv[0]
registry.running_under_test = 'pytest' in sys.argv[0]
registry.initialising = True
return registry

View File

@ -26,6 +26,7 @@ import datetime
import json
import logging
import os
from enum import IntEnum
from tempfile import gettempdir
from PyQt5 import QtCore, QtGui
@ -38,6 +39,13 @@ log = logging.getLogger(__name__)
__version__ = 2
class ProxyMode(IntEnum):
NO_PROXY = 1
SYSTEM_PROXY = 2
MANUAL_PROXY = 3
# Fix for bug #1014422.
X11_BYPASS_DEFAULT = True
if is_linux(): # pragma: no cover
@ -62,7 +70,7 @@ def media_players_conv(string):
return string
def upgrade_monitor(number, x_position, y_position, height, width, can_override, can_display_on_monitor):
def upgrade_screens(number, x_position, y_position, height, width, can_override, is_display_screen):
"""
Upgrade them monitor setting from a few single entries to a composite JSON entry
@ -70,19 +78,23 @@ def upgrade_monitor(number, x_position, y_position, height, width, can_override,
:param int x_position: The X position
:param int y_position: The Y position
:param bool can_override: Are the screen positions overridden
:param bool can_display_on_monitor: Can OpenLP display on the monitor
:param bool is_display_screen: Is this a display screen
:returns dict: Dictionary with the new value
"""
geometry_key = 'geometry'
if can_override:
geometry_key = 'display_geometry'
return {
number: {
'displayGeometry': {
'number': number,
geometry_key: {
'x': x_position,
'y': y_position,
'height': height,
'width': width
}
},
'canDisplayOnMonitor': can_display_on_monitor
},
'is_display': is_display_screen
}
}
@ -140,6 +152,11 @@ class Settings(QtCore.QSettings):
'advanced/print file meta data': False,
'advanced/print notes': False,
'advanced/print slide text': False,
'advanced/proxy mode': ProxyMode.SYSTEM_PROXY,
'advanced/proxy http': '',
'advanced/proxy https': '',
'advanced/proxy username': '',
'advanced/proxy password': '',
'advanced/recent file count': 4,
'advanced/save current plugin': False,
'advanced/slide limits': SlideLimits.End,
@ -224,6 +241,7 @@ class Settings(QtCore.QSettings):
'projector/db database': '',
'projector/enable': True,
'projector/connect on start': False,
'projector/connect when LKUP received': True, # PJLink v2: Projector sends LKUP command after it powers up
'projector/last directory import': None,
'projector/last directory export': None,
'projector/poll time': 20, # PJLink timeout is 30 seconds
@ -287,7 +305,7 @@ class Settings(QtCore.QSettings):
('songuasge/db database', 'songusage/db database', []),
('presentations / Powerpoint Viewer', '', []),
(['core/monitor', 'core/x position', 'core/y position', 'core/height', 'core/width', 'core/override',
'core/display on monitor'], 'core/monitors', [(upgrade_monitor, [1, 0, 0, None, None, False, False])])
'core/display on monitor'], 'core/screens', [(upgrade_screens, [1, 0, 0, None, None, False, False])])
]
@staticmethod
@ -553,7 +571,7 @@ class Settings(QtCore.QSettings):
:param value: The value to save
:rtype: None
"""
if isinstance(value, Path) or (isinstance(value, list) and value and isinstance(value[0], Path)):
if isinstance(value, (Path, dict)) or (isinstance(value, list) and value and isinstance(value[0], Path)):
value = json.dumps(value, cls=OpenLPJsonEncoder)
super().setValue(key, value)
@ -576,6 +594,9 @@ class Settings(QtCore.QSettings):
# An empty list saved to the settings results in a None type being returned.
elif isinstance(default_value, list):
return []
# An empty dictionary saved to the settings results in a None type being returned.
elif isinstance(default_value, dict):
return {}
elif isinstance(setting, str):
if '__Path__' in setting or setting.startswith('{'):
return json.loads(setting, cls=OpenLPJsonDecoder)

View File

@ -115,6 +115,8 @@ class Screen(object):
self.is_display = screen_dict['is_display']
self.is_primary = screen_dict['is_primary']
self.geometry = QtCore.QRect(**screen_dict['geometry'])
if 'display_geometry' in screen_dict:
self.display_geometry = QtCore.QRect(**screen_dict['display_geometry'])
class ScreenList(object):
@ -197,26 +199,26 @@ class ScreenList(object):
def load_screen_settings(self):
"""
Loads the screen size and the monitor number from the settings.
Loads the screen size and the screen number from the settings.
"""
# Add the screen settings to the settings dict. This has to be done here due to cyclic dependency.
# Do not do this anywhere else.
screen_settings = {
'core/monitors': '{}'
'core/screens': '{}'
}
Settings.extend_default_settings(screen_settings)
monitors = Settings().value('core/monitors')
# for number, monitor in monitors.items():
# if self.has_screen(number):
# self[number].update(monitor)
# else:
# self.screens.append(Screen.from_dict(monitor))
screen_settings = Settings().value('core/screens')
for number, screen_dict in screen_settings.items():
if self.has_screen(number):
self[number].update(screen_dict)
else:
self.screens.append(Screen.from_dict(screen_dict))
def save_screen_settings(self):
"""
Saves the screen size and monitor settings
Saves the screen size and screen settings
"""
Settings().setValue('core/monitors', {screen.number: screen.to_dict() for screen in self.screens})
Settings().setValue('core/screens', {screen.number: screen.to_dict() for screen in self.screens})
def get_display_screen_list(self):
"""

View File

@ -19,7 +19,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
r"""
This module is responsible for generating the HTML for :class:`~openlp.core.ui.maindisplay`. The ``build_html`` function
is the function which has to be called from outside. The generated and returned HTML will look similar to this::
@ -415,7 +415,7 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, Vertic
log = logging.getLogger(__name__)
HTML_SRC = Template("""
HTML_SRC = Template(r"""
<!DOCTYPE html>
<html>
<head>

View File

@ -28,6 +28,7 @@ import re
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.registry import Registry
@ -165,28 +166,25 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
toolbar_actions = []
# Import Button
if self.has_import_icon:
toolbar_actions.append(['Import', StringContent.Import,
':/general/general_import.png', self.on_import_click])
toolbar_actions.append(['Import', StringContent.Import, UiIcons().download, self.on_import_click])
# Load Button
if self.has_file_icon:
toolbar_actions.append(['Load', StringContent.Load, ':/general/general_open.png', self.on_file_click])
toolbar_actions.append(['Load', StringContent.Load, UiIcons().open, self.on_file_click])
# New Button
if self.has_new_icon:
toolbar_actions.append(['New', StringContent.New, ':/general/general_new.png', self.on_new_click])
toolbar_actions.append(['New', StringContent.New, UiIcons().new, self.on_new_click])
# Edit Button
if self.has_edit_icon:
toolbar_actions.append(['Edit', StringContent.Edit, ':/general/general_edit.png', self.on_edit_click])
toolbar_actions.append(['Edit', StringContent.Edit, UiIcons().edit, self.on_edit_click])
# Delete Button
if self.has_delete_icon:
toolbar_actions.append(['Delete', StringContent.Delete,
':/general/general_delete.png', self.on_delete_click])
toolbar_actions.append(['Delete', StringContent.Delete, UiIcons().delete, self.on_delete_click])
# Preview
toolbar_actions.append(['Preview', StringContent.Preview,
':/general/general_preview.png', self.on_preview_click])
toolbar_actions.append(['Preview', StringContent.Preview, UiIcons().preview, self.on_preview_click])
# Live Button
toolbar_actions.append(['Live', StringContent.Live, ':/general/general_live.png', self.on_live_click])
toolbar_actions.append(['Live', StringContent.Live, UiIcons().live, self.on_live_click])
# Add to service Button
toolbar_actions.append(['Service', StringContent.Service, ':/general/general_add.png', self.on_add_click])
toolbar_actions.append(['Service', StringContent.Service, UiIcons().add, self.on_add_click])
for action in toolbar_actions:
if action[0] == StringContent.Preview:
self.toolbar.addSeparator()
@ -207,21 +205,21 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
if self.has_edit_icon:
create_widget_action(self.list_view,
text=self.plugin.get_string(StringContent.Edit)['title'],
icon=':/general/general_edit.png',
icon=UiIcons().edit,
triggers=self.on_edit_click)
create_widget_action(self.list_view, separator=True)
create_widget_action(self.list_view,
'listView{plugin}{preview}Item'.format(plugin=self.plugin.name.title(),
preview=StringContent.Preview.title()),
text=self.plugin.get_string(StringContent.Preview)['title'],
icon=':/general/general_preview.png',
icon=UiIcons().preview,
can_shortcuts=True,
triggers=self.on_preview_click)
create_widget_action(self.list_view,
'listView{plugin}{live}Item'.format(plugin=self.plugin.name.title(),
live=StringContent.Live.title()),
text=self.plugin.get_string(StringContent.Live)['title'],
icon=':/general/general_live.png',
icon=UiIcons().live,
can_shortcuts=True,
triggers=self.on_live_click)
create_widget_action(self.list_view,
@ -229,7 +227,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
service=StringContent.Service.title()),
can_shortcuts=True,
text=self.plugin.get_string(StringContent.Service)['title'],
icon=':/general/general_add.png',
icon=UiIcons().add,
triggers=self.on_add_click)
if self.has_delete_icon:
create_widget_action(self.list_view, separator=True)
@ -237,13 +235,13 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
'listView{plugin}{delete}Item'.format(plugin=self.plugin.name.title(),
delete=StringContent.Delete.title()),
text=self.plugin.get_string(StringContent.Delete)['title'],
icon=':/general/general_delete.png',
icon=UiIcons().delete,
can_shortcuts=True, triggers=self.on_delete_click)
if self.add_to_service_item:
create_widget_action(self.list_view, separator=True)
create_widget_action(self.list_view,
text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'),
icon=':/general/general_add.png',
icon=UiIcons().add,
triggers=self.on_add_edit_click)
self.add_custom_context_actions()
# Create the context menu and add all actions from the list_view.
@ -621,7 +619,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
:param context: The context on which this is called
"""
service_item = ServiceItem(self.plugin)
service_item.add_icon(self.plugin.icon_path)
service_item.add_icon()
if self.generate_slide_data(service_item, item, xml_version, remote, context):
return service_item
else:

View File

@ -35,6 +35,7 @@ from PyQt5 import QtGui
from openlp.core.common import md5_hash
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.path import Path
from openlp.core.common.settings import Settings
@ -173,7 +174,7 @@ class ServiceItem(RegistryProperties):
self.processor = None
self.audit = ''
self.items = []
self.iconic_representation = None
self.icon = UiIcons().default
self.raw_footer = []
self.foot_text = ''
self.theme = None
@ -231,14 +232,22 @@ class ServiceItem(RegistryProperties):
"""
return capability in self.capabilities
def add_icon(self, icon):
def add_icon(self):
"""
Add an icon to the service item. This is used when displaying the service item in the service manager.
:param icon: A string to an icon in the resources or on disk.
"""
self.icon = icon
self.iconic_representation = build_icon(icon)
if self.name == 'songs':
self.icon = UiIcons().music
elif self.name == 'bibles':
self.icon = UiIcons().bible
elif self.name == 'presentations':
self.icon = UiIcons().presentation
elif self.name == 'images':
self.icon = UiIcons().picture
elif self.name == 'media':
self.icon = UiIcons().video
else:
self.icon = UiIcons().clone
@property
def rendered_slides(self):
@ -392,7 +401,6 @@ class ServiceItem(RegistryProperties):
'plugin': self.name,
'theme': self.theme,
'title': self.title,
'icon': self.icon,
'footer': self.raw_footer,
'type': self.service_item_type,
'audit': self.audit,
@ -444,7 +452,7 @@ class ServiceItem(RegistryProperties):
self.name = header['name']
self.service_item_type = header['type']
self.theme = header['theme']
self.add_icon(header['icon'])
self.add_icon()
self.raw_footer = header['footer']
self.audit = header['audit']
self.notes = header['notes']

View File

@ -31,6 +31,7 @@ from openlp.core.common.actions import ActionList
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
log = logging.getLogger(__name__)
@ -161,10 +162,10 @@ def create_button(parent, name, **kwargs):
kwargs.setdefault('text', UiStrings().Delete)
kwargs.setdefault('tooltip', translate('OpenLP.Ui', 'Delete the selected item.'))
elif role == 'up':
kwargs.setdefault('icon', ':/services/service_up.png')
kwargs.setdefault('icon', UiIcons().arrow_up)
kwargs.setdefault('tooltip', translate('OpenLP.Ui', 'Move selection up one position.'))
elif role == 'down':
kwargs.setdefault('icon', ':/services/service_down.png')
kwargs.setdefault('icon', UiIcons().arrow_down)
kwargs.setdefault('tooltip', translate('OpenLP.Ui', 'Move selection down one position.'))
else:
log.warning('The role "{role}" is not defined in create_push_button().'.format(role=role))

View File

@ -154,110 +154,137 @@ PROJECTOR_STATE = [
S_INFO
]
# NOTE: Changed format to account for some commands are both class 1 and 2
# NOTE: Changed format to account for some commands are both class 1 and 2.
# Make sure the sequence of 'version' is lowest-to-highest.
PJLINK_VALID_CMD = {
'ACKN': {'version': ['2', ],
'ACKN': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Acknowledge a PJLink SRCH command - returns MAC address.')
},
'AVMT': {'version': ['1', ],
'AVMT': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Blank/unblank video and/or mute audio.')
},
'CLSS': {'version': ['1', ],
'CLSS': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query projector PJLink class support.')
},
'ERST': {'version': ['1', '2'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query error status from projector. '
'Returns fan/lamp/temp/cover/filter/other error status.')
},
'FILT': {'version': ['2', ],
'FILT': {'version': ['2'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query number of hours on filter.')
},
'FREZ': {'version': ['2', ],
'FREZ': {'version': ['2'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Freeze or unfreeze current image being projected.')
},
'INF1': {'version': ['1', ],
'INF1': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query projector manufacturer name.')
},
'INF2': {'version': ['1', ],
'INF2': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query projector product name.')
},
'INFO': {'version': ['1', ],
'INFO': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query projector for other information set by manufacturer.')
},
'INNM': {'version': ['2', ],
'INNM': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query specified input source name')
},
'INPT': {'version': ['1', ],
'INPT': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Switch to specified video source.')
},
'INST': {'version': ['1', ],
'INST': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query available input sources.')
},
'IRES': {'version:': ['2', ],
'IRES': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query current input resolution.')
},
'LAMP': {'version': ['1', ],
'LAMP': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query lamp time and on/off status. Multiple lamps supported.')
},
'LKUP': {'version': ['2', ],
'LKUP': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'UDP Status - Projector is now available on network. Includes MAC address.')
},
'MVOL': {'version': ['2', ],
'MVOL': {'version': ['2'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Adjust microphone volume by 1 step.')
},
'NAME': {'version': ['1', ],
'NAME': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Query customer-set projector name.')
},
'PJLINK': {'version': ['1', ],
'PJLINK': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Initial connection with authentication/no authentication request.')
},
'POWR': {'version': ['1', ],
'POWR': {'version': ['1'],
'default': '1',
'description': translate('OpenLP.PJLinkConstants',
'Turn lamp on or off/standby.')
},
'RFIL': {'version': ['2', ],
'RFIL': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query replacement air filter model number.')
},
'RLMP': {'version': ['2', ],
'RLMP': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query replacement lamp model number.')
},
'RRES': {'version': ['2', ],
'RRES': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query recommended resolution.')
},
'SNUM': {'version': ['2', ],
'SNUM': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query projector serial number.')
},
'SRCH': {'version': ['2', ],
'SRCH': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'UDP broadcast search request for available projectors. Reply is ACKN.')
},
'SVER': {'version': ['2', ],
'SVER': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Query projector software version number.')
},
'SVOL': {'version': ['2', ],
'SVOL': {'version': ['2'],
'default': '2',
'description': translate('OpenLP.PJLinkConstants',
'Adjust speaker volume by 1 step.')
}

View File

@ -29,7 +29,7 @@ from PyQt5 import QtCore, QtWidgets
from openlp.core.common import verify_ip_address
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
from openlp.core.projectors.constants import PJLINK_PORT
from openlp.core.projectors.db import Projector
@ -47,7 +47,7 @@ class Ui_ProjectorEditForm(object):
Create the interface layout.
"""
edit_projector_dialog.setObjectName('edit_projector_dialog')
edit_projector_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
edit_projector_dialog.setWindowIcon(UiIcons().main_icon)
edit_projector_dialog.setMinimumWidth(400)
edit_projector_dialog.setModal(True)
# Define the basic layout
@ -58,10 +58,15 @@ class Ui_ProjectorEditForm(object):
# IP Address
self.ip_label = QtWidgets.QLabel(edit_projector_dialog)
self.ip_label.setObjectName('projector_edit_ip_label')
self.ip_text = QtWidgets.QLineEdit(edit_projector_dialog)
self.ip_text.setObjectName('projector_edit_ip_text')
self.ip_text_edit = QtWidgets.QLineEdit(edit_projector_dialog)
self.ip_text_edit.setObjectName('projector_edit_ip_text')
self.ip_text_label = QtWidgets.QLabel(edit_projector_dialog)
self.ip_text_label.setObjectName('projector_show_ip_text')
self.dialog_layout.addWidget(self.ip_label, 0, 0)
self.dialog_layout.addWidget(self.ip_text, 0, 1)
# For new projector, use edit widget
self.dialog_layout.addWidget(self.ip_text_edit, 0, 1)
# For edit projector, use show widget
self.dialog_layout.addWidget(self.ip_text_label, 0, 1)
# Port number
self.port_label = QtWidgets.QLabel(edit_projector_dialog)
self.port_label.setObjectName('projector_edit_ip_label')
@ -111,8 +116,8 @@ class Ui_ProjectorEditForm(object):
title = translate('OpenLP.ProjectorEditForm', 'Edit Projector')
edit_projector_dialog.setWindowTitle(title)
self.ip_label.setText(translate('OpenLP.ProjectorEditForm', 'IP Address'))
self.ip_text.setText(self.projector.ip)
self.ip_text.setFocus()
self.ip_text_edit.setText(self.projector.ip)
self.ip_text_label.setText(self.projector.ip)
self.port_label.setText(translate('OpenLP.ProjectorEditForm', 'Port Number'))
self.port_text.setText(str(self.projector.port))
self.pin_label.setText(translate('OpenLP.ProjectorEditForm', 'PIN'))
@ -131,7 +136,7 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm):
Class to add or edit a projector entry in the database.
Fields that are editable:
ip = Column(String(100))
ip = Column(String(100)) (Only edit for new projector)
port = Column(String(8))
pin = Column(String(20))
name = Column(String(20))
@ -154,9 +159,16 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm):
if projector is None:
self.projector = Projector()
self.new_projector = True
self.ip_text_edit.setVisible(True)
self.ip_text_edit.setFocus()
self.ip_text_label.setVisible(False)
else:
self.projector = projector
self.new_projector = False
self.ip_text_edit.setVisible(False)
self.ip_text_label.setVisible(True)
# Since it's already defined, IP address is unchangeable, so focus on port number
self.port_text.setFocus()
self.retranslateUi(self)
reply = QtWidgets.QDialog.exec(self)
return reply
@ -187,30 +199,32 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm):
record=record.id)))
valid = False
return
adx = self.ip_text.text()
valid = verify_ip_address(adx)
if valid:
ip = self.projectordb.get_projector_by_ip(adx)
if ip is None:
valid = True
self.new_projector = True
elif ip.id != self.projector.id:
if self.new_projector:
# Only validate a new entry - otherwise it's been previously verified
adx = self.ip_text_edit.text()
valid = verify_ip_address(adx)
if valid:
# With a valid IP - check if it's already in database so we don't duplicate
ip = self.projectordb.get_projector_by_ip(adx)
if ip is None:
valid = True
self.new_projector = True
elif ip.id != self.projector.id:
QtWidgets.QMessageBox.warning(self,
translate('OpenLP.ProjectorWizard', 'Duplicate IP Address'),
translate('OpenLP.ProjectorWizard',
'IP address "{ip}"<br />is already in the database '
'as ID {data}.<br /><br />Please Enter a different '
'IP address.'.format(ip=adx, data=ip.id)))
return
else:
QtWidgets.QMessageBox.warning(self,
translate('OpenLP.ProjectorWizard', 'Duplicate IP Address'),
translate('OpenLP.ProjectorWizard', 'Invalid IP Address'),
translate('OpenLP.ProjectorWizard',
'IP address "{ip}"<br />is already in the database '
'as ID {data}.<br /><br />Please Enter a different '
'IP address.'.format(ip=adx, data=ip.id)))
'IP address "{ip}"<br>is not a valid IP address.'
'<br /><br />Please enter a valid IP address.'.format(ip=adx)))
valid = False
return
else:
QtWidgets.QMessageBox.warning(self,
translate('OpenLP.ProjectorWizard', 'Invalid IP Address'),
translate('OpenLP.ProjectorWizard',
'IP address "{ip}"<br>is not a valid IP address.'
'<br /><br />Please enter a valid IP address.'.format(ip=adx)))
valid = False
return
port = int(self.port_text.text())
if port < 1000 or port > 32767:
QtWidgets.QMessageBox.warning(self,
@ -223,7 +237,8 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm):
'Default PJLink port is {port}'.format(port=PJLINK_PORT)))
valid = False
if valid:
self.projector.ip = self.ip_text.text()
if self.new_projector:
self.projector.ip = self.ip_text_edit.text()
self.projector.pin = self.pin_text.text()
self.projector.port = int(self.port_text.text())
self.projector.name = self.name_text.text()

View File

@ -30,29 +30,15 @@ import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.mixins import LogMixin, RegistryProperties
from openlp.core.common.registry import RegistryBase
from openlp.core.common.settings import Settings
from openlp.core.lib.ui import create_widget_action
from openlp.core.projectors import DialogSourceStyle
from openlp.core.projectors.constants import \
E_AUTHENTICATION, \
E_ERROR, \
E_NETWORK, \
E_NOT_CONNECTED, \
E_UNKNOWN_SOCKET_ERROR, \
S_CONNECTED, \
S_CONNECTING, \
S_COOLDOWN, \
S_INITIALIZE, \
S_NOT_CONNECTED, \
S_OFF, \
S_ON, \
S_STANDBY, \
S_WARMUP, \
STATUS_CODE, \
STATUS_MSG, \
QSOCKET_STATE
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, \
E_SOCKET_TIMEOUT, E_UNKNOWN_SOCKET_ERROR, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, \
S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP, PJLINK_PORT, STATUS_CODE, STATUS_MSG, QSOCKET_STATE
from openlp.core.projectors.db import ProjectorDB
from openlp.core.projectors.editform import ProjectorEditForm
@ -77,6 +63,7 @@ STATUS_ICONS = {
S_COOLDOWN: ':/projector/projector_cooldown.png',
E_ERROR: ':/projector/projector_error.png',
E_NETWORK: ':/projector/projector_not_connected_error.png',
E_SOCKET_TIMEOUT: ':/projector/projector_not_connected_error.png',
E_AUTHENTICATION: ':/projector/projector_not_connected_error.png',
E_UNKNOWN_SOCKET_ERROR: ':/projector/projector_not_connected_error.png',
E_NOT_CONNECTED: ':/projector/projector_not_connected_error.png'
@ -103,30 +90,30 @@ class UiProjectorManager(object):
self.one_toolbar = OpenLPToolbar(widget)
self.one_toolbar.add_toolbar_action('new_projector',
text=translate('OpenLP.ProjectorManager', 'Add Projector'),
icon=':/projector/projector_new.png',
icon=UiIcons().new,
tooltip=translate('OpenLP.ProjectorManager', 'Add a new projector.'),
triggers=self.on_add_projector)
# Show edit/delete when projector not connected
self.one_toolbar.add_toolbar_action('edit_projector',
text=translate('OpenLP.ProjectorManager', 'Edit Projector'),
icon=':/general/general_edit.png',
icon=UiIcons().edit,
tooltip=translate('OpenLP.ProjectorManager', 'Edit selected projector.'),
triggers=self.on_edit_projector)
self.one_toolbar.add_toolbar_action('delete_projector',
text=translate('OpenLP.ProjectorManager', 'Delete Projector'),
icon=':/general/general_delete.png',
icon=UiIcons().delete,
tooltip=translate('OpenLP.ProjectorManager', 'Delete selected projector.'),
triggers=self.on_delete_projector)
# Show source/view when projector connected
self.one_toolbar.add_toolbar_action('source_view_projector',
text=translate('OpenLP.ProjectorManager', 'Select Input Source'),
icon=':/projector/projector_hdmi.png',
icon=UiIcons().projector_hdmi,
tooltip=translate('OpenLP.ProjectorManager',
'Choose input source on selected projector.'),
triggers=self.on_select_input)
self.one_toolbar.add_toolbar_action('view_projector',
text=translate('OpenLP.ProjectorManager', 'View Projector'),
icon=':/system/system_about.png',
icon=UiIcons().info,
tooltip=translate('OpenLP.ProjectorManager',
'View selected projector information.'),
triggers=self.on_status_projector)
@ -134,28 +121,28 @@ class UiProjectorManager(object):
self.one_toolbar.add_toolbar_action('connect_projector',
text=translate('OpenLP.ProjectorManager',
'Connect to selected projector.'),
icon=':/projector/projector_connect.png',
icon=UiIcons().projector_connect,
tooltip=translate('OpenLP.ProjectorManager',
'Connect to selected projector.'),
triggers=self.on_connect_projector)
self.one_toolbar.add_toolbar_action('connect_projector_multiple',
text=translate('OpenLP.ProjectorManager',
'Connect to selected projectors'),
icon=':/projector/projector_connect_tiled.png',
icon=UiIcons().projector_connect,
tooltip=translate('OpenLP.ProjectorManager',
'Connect to selected projectors.'),
triggers=self.on_connect_projector)
self.one_toolbar.add_toolbar_action('disconnect_projector',
text=translate('OpenLP.ProjectorManager',
'Disconnect from selected projectors'),
icon=':/projector/projector_disconnect.png',
icon=UiIcons().projector_disconnect,
tooltip=translate('OpenLP.ProjectorManager',
'Disconnect from selected projector.'),
triggers=self.on_disconnect_projector)
self.one_toolbar.add_toolbar_action('disconnect_projector_multiple',
text=translate('OpenLP.ProjectorManager',
'Disconnect from selected projector'),
icon=':/projector/projector_disconnect_tiled.png',
icon=UiIcons().projector_disconnect,
tooltip=translate('OpenLP.ProjectorManager',
'Disconnect from selected projectors.'),
triggers=self.on_disconnect_projector)
@ -163,26 +150,26 @@ class UiProjectorManager(object):
self.one_toolbar.add_toolbar_action('poweron_projector',
text=translate('OpenLP.ProjectorManager',
'Power on selected projector'),
icon=':/projector/projector_power_on.png',
icon=UiIcons().projector_on,
tooltip=translate('OpenLP.ProjectorManager',
'Power on selected projector.'),
triggers=self.on_poweron_projector)
self.one_toolbar.add_toolbar_action('poweron_projector_multiple',
text=translate('OpenLP.ProjectorManager',
'Power on selected projector'),
icon=':/projector/projector_power_on_tiled.png',
icon=UiIcons().projector_on,
tooltip=translate('OpenLP.ProjectorManager',
'Power on selected projectors.'),
triggers=self.on_poweron_projector)
self.one_toolbar.add_toolbar_action('poweroff_projector',
text=translate('OpenLP.ProjectorManager', 'Standby selected projector'),
icon=':/projector/projector_power_off.png',
icon=UiIcons().projector_off,
tooltip=translate('OpenLP.ProjectorManager',
'Put selected projector in standby.'),
triggers=self.on_poweroff_projector)
self.one_toolbar.add_toolbar_action('poweroff_projector_multiple',
text=translate('OpenLP.ProjectorManager', 'Standby selected projector'),
icon=':/projector/projector_power_off_tiled.png',
icon=UiIcons().projector_off,
tooltip=translate('OpenLP.ProjectorManager',
'Put selected projectors in standby.'),
triggers=self.on_poweroff_projector)
@ -190,28 +177,28 @@ class UiProjectorManager(object):
self.one_toolbar.add_toolbar_action('blank_projector',
text=translate('OpenLP.ProjectorManager',
'Blank selected projector screen'),
icon=':/projector/projector_blank.png',
icon=UiIcons().blank,
tooltip=translate('OpenLP.ProjectorManager',
'Blank selected projector screen'),
triggers=self.on_blank_projector)
self.one_toolbar.add_toolbar_action('blank_projector_multiple',
text=translate('OpenLP.ProjectorManager',
'Blank selected projectors screen'),
icon=':/projector/projector_blank_tiled.png',
icon=UiIcons().blank,
tooltip=translate('OpenLP.ProjectorManager',
'Blank selected projectors screen.'),
triggers=self.on_blank_projector)
self.one_toolbar.add_toolbar_action('show_projector',
text=translate('OpenLP.ProjectorManager',
'Show selected projector screen'),
icon=':/projector/projector_show.png',
icon=UiIcons().desktop,
tooltip=translate('OpenLP.ProjectorManager',
'Show selected projector screen.'),
triggers=self.on_show_projector)
self.one_toolbar.add_toolbar_action('show_projector_multiple',
text=translate('OpenLP.ProjectorManager',
'Show selected projector screen'),
icon=':/projector/projector_show_tiled.png',
icon=UiIcons().desktop,
tooltip=translate('OpenLP.ProjectorManager',
'Show selected projectors screen.'),
triggers=self.on_show_projector)
@ -233,61 +220,61 @@ class UiProjectorManager(object):
self.status_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'&View Projector Information'),
icon=':/system/system_about.png',
icon=UiIcons().info,
triggers=self.on_status_projector)
self.edit_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'&Edit Projector'),
icon=':/projector/projector_edit.png',
icon=UiIcons().edit,
triggers=self.on_edit_projector)
self.menu.addSeparator()
self.connect_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'&Connect Projector'),
icon=':/projector/projector_connect.png',
icon=UiIcons().projector_connect,
triggers=self.on_connect_projector)
self.disconnect_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'D&isconnect Projector'),
icon=':/projector/projector_disconnect.png',
icon=UiIcons().projector_off,
triggers=self.on_disconnect_projector)
self.menu.addSeparator()
self.poweron_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'Power &On Projector'),
icon=':/projector/projector_power_on.png',
icon=UiIcons().projector_on,
triggers=self.on_poweron_projector)
self.poweroff_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'Power O&ff Projector'),
icon=':/projector/projector_power_off.png',
icon=UiIcons().projector_off,
triggers=self.on_poweroff_projector)
self.menu.addSeparator()
self.select_input_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'Select &Input'),
icon=':/projector/projector_hdmi.png',
icon=UiIcons().projector_hdmi,
triggers=self.on_select_input)
self.edit_input_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'Edit Input Source'),
icon=':/general/general_edit.png',
icon=UiIcons().edit,
triggers=self.on_edit_input)
self.blank_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'&Blank Projector Screen'),
icon=':/projector/projector_blank.png',
icon=UiIcons().blank,
triggers=self.on_blank_projector)
self.show_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'&Show Projector Screen'),
icon=':/projector/projector_show.png',
icon=UiIcons().projector,
triggers=self.on_show_projector)
self.menu.addSeparator()
self.delete_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager',
'&Delete Projector'),
icon=':/general/general_delete.png',
icon=UiIcons().delete,
triggers=self.on_delete_projector)
self.update_icons()
@ -309,6 +296,27 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
self.projectordb = projectordb
self.projector_list = []
self.source_select_form = None
# Dictionary of PJLinkUDP objects to listen for UDP broadcasts from PJLink 2+ projectors.
# Key is port number that projectors use
self.pjlink_udp = {}
# Dict for matching projector status to display icon
self.status_icons = {
S_NOT_CONNECTED: UiIcons().projector_disconnect,
S_CONNECTING: UiIcons().projector_connect,
S_CONNECTED: UiIcons().projector_off,
S_OFF: UiIcons().projector_off,
S_INITIALIZE: UiIcons().projector_on,
S_STANDBY: UiIcons().projector_off,
S_WARMUP: UiIcons().projector_warmup,
S_ON: UiIcons().projector_off,
S_COOLDOWN: UiIcons().projector_cooldown,
E_ERROR: UiIcons().projector_error,
E_NETWORK: UiIcons().error,
E_SOCKET_TIMEOUT: UiIcons().authentication,
E_AUTHENTICATION: UiIcons().authentication,
E_UNKNOWN_SOCKET_ERROR: UiIcons().error,
E_NOT_CONNECTED: UiIcons().projector_disconnect
}
def bootstrap_initialise(self):
"""
@ -322,12 +330,15 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
else:
log.debug('Using existing ProjectorDB() instance')
self.get_settings()
self.pjlink_udp = PJLinkUDP(self.projector_list)
def bootstrap_post_set_up(self):
"""
Post-initialize setups.
"""
# Default PJLink port UDP socket
log.debug('Creating PJLinkUDP listener for default port {port}'.format(port=PJLINK_PORT))
self.pjlink_udp = {PJLINK_PORT: PJLinkUDP(port=PJLINK_PORT)}
self.pjlink_udp[PJLINK_PORT].bind(PJLINK_PORT)
# Set 1.5 second delay before loading all projectors
if self.autostart:
log.debug('Delaying 1.5 seconds before loading all projectors')
@ -345,14 +356,10 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
Retrieve the saved settings
"""
log.debug('Updating ProjectorManager settings')
settings = Settings()
settings.beginGroup(self.settings_section)
self.autostart = settings.value('connect on start')
self.poll_time = settings.value('poll time')
self.socket_timeout = settings.value('socket timeout')
self.source_select_dialog_type = settings.value('source dialog type')
settings.endGroup()
del settings
self.autostart = Settings().value('projector/connect on start')
self.poll_time = Settings().value('projector/poll time')
self.socket_timeout = Settings().value('projector/socket timeout')
self.source_select_dialog_type = Settings().value('projector/source dialog type')
def context_menu(self, point):
"""
@ -373,22 +380,14 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
self.connect_action.setVisible(not visible)
self.disconnect_action.setVisible(visible)
self.status_action.setVisible(visible)
if visible:
self.select_input_action.setVisible(real_projector.link.power == S_ON)
self.edit_input_action.setVisible(real_projector.link.power == S_ON)
self.poweron_action.setVisible(real_projector.link.power == S_STANDBY)
self.poweroff_action.setVisible(real_projector.link.power == S_ON)
self.blank_action.setVisible(real_projector.link.power == S_ON and
not real_projector.link.shutter)
self.show_action.setVisible(real_projector.link.power == S_ON and
real_projector.link.shutter)
else:
self.select_input_action.setVisible(False)
self.edit_input_action.setVisible(False)
self.poweron_action.setVisible(False)
self.poweroff_action.setVisible(False)
self.blank_action.setVisible(False)
self.show_action.setVisible(False)
self.select_input_action.setVisible(visible and real_projector.link.power == S_ON)
self.edit_input_action.setVisible(visible and real_projector.link.power == S_ON)
self.poweron_action.setVisible(visible and real_projector.link.power == S_STANDBY)
self.poweroff_action.setVisible(visible and real_projector.link.power == S_ON)
self.blank_action.setVisible(visible and real_projector.link.power == S_ON and
not real_projector.link.shutter)
self.show_action.setVisible(visible and real_projector.link.power == S_ON and
real_projector.link.shutter)
self.menu.projector = real_projector
self.menu.exec(self.projector_list_widget.mapToGlobal(point))
@ -528,6 +527,13 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
projector.socket_timer.timeout.disconnect(projector.link.socket_abort)
except (AttributeError, TypeError):
pass
# Disconnect signals from projector being deleted
try:
self.pjlink_udp[projector.link.port].data_received.disconnect(projector.link.get_buffer)
except (AttributeError, TypeError):
pass
# Rebuild projector list
new_list = []
for item in self.projector_list:
if item.link.db_item.id == projector.link.db_item.id:
@ -655,6 +661,21 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
data=projector.link.manufacturer)
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Model'),
data=projector.link.model)
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'PJLink Class'),
data=projector.link.pjlink_class)
if projector.link.pjlink_class != 1:
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager',
'Software Version'),
data=projector.link.sw_version)
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager',
'Serial Number'),
data=projector.link.serial_no)
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager',
'Lamp Model Number'),
data=projector.link.model_lamp)
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager',
'Filter Model Number'),
data=projector.link.model_filter)
message += '<b>{title}</b>: {data}<br /><br />'.format(title=translate('OpenLP.ProjectorManager',
'Other info'),
data=projector.link.other_info)
@ -668,20 +689,6 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
source=translate('OpenLP.ProjectorManager',
'Current source input is'),
selected=projector.link.source)
if projector.link.pjlink_class == '2':
# Information only available for PJLink Class 2 projectors
message += '<b>{title}</b>: {data}<br /><br />'.format(title=translate('OpenLP.ProjectorManager',
'Serial Number'),
data=projector.serial_no)
message += '<b>{title}</b>: {data}<br /><br />'.format(title=translate('OpenLP.ProjectorManager',
'Software Version'),
data=projector.sw_version)
message += '<b>{title}</b>: {data}<br /><br />'.format(title=translate('OpenLP.ProjectorManager',
'Lamp type'),
data=projector.model_lamp)
message += '<b>{title}</b>: {data}<br /><br />'.format(title=translate('OpenLP.ProjectorManager',
'Filter type'),
data=projector.model_filter)
count = 1
for item in projector.link.lamp:
if item['On'] is None:
@ -729,7 +736,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
"""
item = ProjectorItem(link=self._add_projector(projector))
item.db_item = projector
item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[S_NOT_CONNECTED]))
item.icon = QtGui.QIcon(self.status_icons[S_NOT_CONNECTED])
widget = QtWidgets.QListWidgetItem(item.icon,
item.link.name,
self.projector_list_widget
@ -741,6 +748,15 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
item.link.projectorAuthentication.connect(self.authentication_error)
item.link.projectorNoAuthentication.connect(self.no_authentication_error)
item.link.projectorUpdateIcons.connect(self.update_icons)
# Connect UDP signal to projector instances with same port
if item.link.port not in self.pjlink_udp:
log.debug('Adding new PJLinkUDP listener fo port {port}'.format(port=item.link.port))
self.pjlink_udp[item.link.port] = PJLinkUDP(port=item.link.port)
self.pjlink_udp[item.link.port].bind(item.link.port)
log.debug('Connecting PJLinkUDP port {port} signal to "{item}"'.format(port=item.link.port,
item=item.link.name))
self.pjlink_udp[item.link.port].data_received.connect(item.link.get_buffer)
self.projector_list.append(item)
if start:
item.link.connect_to_host()
@ -816,7 +832,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
return
item.status = status
item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
item.icon = self.status_icons[status]
log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=STATUS_CODE[status]))
item.widget.setIcon(item.icon)
return self.update_icons()
@ -953,6 +969,10 @@ class ProjectorItem(QtCore.QObject):
self.poll_time = None
self.socket_timeout = None
self.status = S_NOT_CONNECTED
self.serial_no = None
self.sw_version = None
self.model_filter = None
self.model_lamp = None
super().__init__()

View File

@ -54,12 +54,12 @@ from PyQt5 import QtCore, QtNetwork
from openlp.core.common import qmd5_hash
from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings
from openlp.core.projectors.constants import CONNECTION_ERRORS, PJLINK_CLASS, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \
PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PREFIX, PJLINK_PORT, PJLINK_POWR_STATUS, \
PJLINK_SUFFIX, PJLINK_VALID_CMD, PROJECTOR_STATE, STATUS_CODE, STATUS_MSG, QSOCKET_STATE, \
E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, \
E_SOCKET_TIMEOUT, \
S_CONNECTED, S_CONNECTING, S_NOT_CONNECTED, S_OFF, S_OK, S_ON
E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT, \
S_CONNECTED, S_CONNECTING, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STANDBY
log = logging.getLogger(__name__)
log.debug('pjlink loaded')
@ -79,38 +79,27 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
"""
Socket service for PJLink UDP socket.
"""
def __init__(self, projector_list, port=PJLINK_PORT):
data_received = QtCore.pyqtSignal(QtNetwork.QHostAddress, int, str, name='udp_data') # host, port, data
def __init__(self, port=PJLINK_PORT):
"""
Socket services for PJLink UDP packets.
Since all UDP packets from any projector will come into the same
port, process UDP packets here then route to the appropriate
projector instance as needed.
:param port: UDP port to listen on
"""
# Keep track of currently defined projectors so we can route
# inbound packets to the correct instance
super().__init__()
self.projector_list = projector_list
self.port = port
# Local defines
self.ackn_list = {} # Replies from online projetors
self.search_active = False
self.search_time = 30000 # 30 seconds for allowed time
self.search_timer = QtCore.QTimer()
# New commands available in PJLink Class 2
# ACKN/SRCH is processed here since it's used to find available projectors
# Other commands are processed by the individual projector instances
self.pjlink_udp_functions = {
'ACKN': self.process_ackn, # Class 2, command is 'SRCH'
'ERST': None, # Class 1/2
'INPT': None, # Class 1/2
'LKUP': None, # Class 2 (reply only - no cmd)
'POWR': None, # Class 1/2
'SRCH': self.process_srch # Class 2 (reply is ACKN)
}
self.readyRead.connect(self.get_datagram)
log.debug('(UDP) PJLinkUDP() Initialized')
log.debug('(UDP) PJLinkUDP() Initialized for port {port}'.format(port=self.port))
@QtCore.pyqtSlot()
def get_datagram(self):
@ -118,88 +107,24 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
Retrieve packet and basic checks
"""
log.debug('(UDP) get_datagram() - Receiving data')
read = self.pendingDatagramSize()
if read < 0:
log.warn('(UDP) No data (-1)')
read_size = self.pendingDatagramSize()
if -1 == read_size:
log.warning('(UDP) No data (-1)')
return
if read < 1:
log.warn('(UDP) get_datagram() called when pending data size is 0')
elif 0 == read_size:
log.warning('(UDP) get_datagram() called when pending data size is 0')
return
data, peer_address, peer_port = self.readDatagram(self.pendingDatagramSize())
elif read_size > PJLINK_MAX_PACKET:
log.warning('(UDP) UDP Packet too large ({size} bytes)- ignoring'.format(size=read_size))
return
data_in, peer_host, peer_port = self.readDatagram(read_size)
data = data_in.decode('utf-8') if isinstance(data_in, bytes) else data_in
log.debug('(UDP) {size} bytes received from {adx} on port {port}'.format(size=len(data),
adx=peer_address,
port=peer_port))
adx=peer_host.toString(),
port=self.port))
log.debug('(UDP) packet "{data}"'.format(data=data))
if len(data) < 0:
log.warn('(UDP) No data (-1)')
return
elif len(data) < 8:
# Minimum packet is '%2CCCC='
log.warn('(UDP) Invalid packet - not enough data')
return
elif data is None:
log.warn('(UDP) No data (None)')
return
elif len(data) > PJLINK_MAX_PACKET:
log.warn('(UDP) Invalid packet - length too long')
return
elif not data.startswith(PJLINK_PREFIX):
log.warn('(UDP) Invalid packet - does not start with PJLINK_PREFIX')
return
elif data[1] != '2':
log.warn('(UDP) Invalid packet - missing/invalid PJLink class version')
return
elif data[6] != '=':
log.warn('(UDP) Invalid packet - separator missing')
return
# First two characters are header information we don't need at this time
cmd, data = data[2:].split('=')
if cmd not in self.pjlink_udp_functions:
log.warn('(UDP) Invalid packet - not a valid PJLink UDP reply')
return
if self.pjlink_udp_functions[cmd] is not None:
log.debug('(UDP) Processing {cmd} with "{data}"'.format(cmd=cmd, data=data))
return self.pjlink_udp_functions[cmd](data=data, host=peer_address, port=peer_port)
else:
log.debug('(UDP) Checking projector list for ip {host} to process'.format(host=peer_address))
for projector in self.projector_list:
if peer_address == projector.ip:
if cmd not in projector.pjlink_functions:
log.error('(UDP) Could not find method to process '
'"{cmd}" in {host}'.format(cmd=cmd, host=projector.ip))
return
log.debug('(UDP) Calling "{cmd}" in {host}'.format(cmd=cmd, host=projector.ip))
return projector.pjlink_functions[cmd](data=data)
log.warn('(UDP) Could not find projector with ip {ip} to process packet'.format(ip=peer_address))
return
def process_ackn(self, data, host, port):
"""
Process the ACKN command.
:param data: Data in packet
:param host: IP address of sending host
:param port: Port received on
"""
log.debug('(UDP) Processing ACKN packet')
if host not in self.ackn_list:
log.debug('(UDP) Adding {host} to ACKN list'.format(host=host))
self.ackn_list[host] = {'data': data,
'port': port}
else:
log.warn('(UDP) Host {host} already replied - ignoring'.format(host=host))
def process_srch(self, data, host, port):
"""
Process the SRCH command.
SRCH is processed by terminals so we ignore any packet.
:param data: Data in packet
:param host: IP address of sending host
:param port: Port received on
"""
log.debug('(UDP) SRCH packet received - ignoring')
log.debug('(UDP) Sending data_received signal to projectors')
self.data_received.emit(peer_host, self.localPort(), data)
return
def search_start(self):
@ -207,7 +132,6 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
Start search for projectors on local network
"""
self.search_active = True
self.ackn_list = {}
# TODO: Send SRCH packet here
self.search_timer.singleShot(self.search_time, self.search_stop)
@ -224,6 +148,8 @@ class PJLinkCommands(object):
"""
Process replies from PJLink projector.
"""
# List of IP addresses and mac addresses found via UDP search command
ackn_list = []
def __init__(self, *args, **kwargs):
"""
@ -231,24 +157,47 @@ class PJLinkCommands(object):
"""
log.debug('PJlinkCommands(args={args} kwargs={kwargs})'.format(args=args, kwargs=kwargs))
super().__init__()
# Map PJLink command to method
# Map PJLink command to method and include pjlink class version for this instance
# Default initial pjlink class version is '1'
self.pjlink_functions = {
'AVMT': self.process_avmt,
'CLSS': self.process_clss,
'ERST': self.process_erst,
'INFO': self.process_info,
'INF1': self.process_inf1,
'INF2': self.process_inf2,
'INPT': self.process_inpt,
'INST': self.process_inst,
'LAMP': self.process_lamp,
'NAME': self.process_name,
'PJLINK': self.process_pjlink,
'POWR': self.process_powr,
'SNUM': self.process_snum,
'SVER': self.process_sver,
'RFIL': self.process_rfil,
'RLMP': self.process_rlmp
'ACKN': {"method": self.process_ackn, # Class 2 (command is SRCH)
"version": "2"},
'AVMT': {"method": self.process_avmt,
"version": "1"},
'CLSS': {"method": self.process_clss,
"version": "1"},
'ERST': {"method": self.process_erst,
"version": "1"},
'INFO': {"method": self.process_info,
"version": "1"},
'INF1': {"method": self.process_inf1,
"version": "1"},
'INF2': {"method": self.process_inf2,
"version": "1"},
'INPT': {"method": self.process_inpt,
"version": "1"},
'INST': {"method": self.process_inst,
"version": "1"},
'LAMP': {"method": self.process_lamp,
"version": "1"},
'LKUP': {"method": self.process_lkup, # Class 2 (reply only - no cmd)
"version": "2"},
'NAME': {"method": self.process_name,
"version": "1"},
'PJLINK': {"method": self.process_pjlink,
"version": "1"},
'POWR': {"method": self.process_powr,
"version": "1"},
'SNUM': {"method": self.process_snum,
"version": "1"},
'SRCH': {"method": self.process_srch, # Class 2 (reply is ACKN)
"version": "2"},
'SVER': {"method": self.process_sver,
"version": "1"},
'RFIL': {"method": self.process_rfil,
"version": "1"},
'RLMP': {"method": self.process_rlmp,
"version": "1"}
}
def reset_information(self):
@ -284,9 +233,16 @@ class PJLinkCommands(object):
if hasattr(self, 'socket_timer'):
log.debug('({ip}): Calling socket_timer.stop()'.format(ip=self.entry.name))
self.socket_timer.stop()
if hasattr(self, 'status_timer'):
log.debug('({ip}): Calling status_timer.stop()'.format(ip=self.entry.name))
self.status_timer.stop()
self.status_timer_checks = {}
self.send_busy = False
self.send_queue = []
self.priority_queue = []
# Reset default version in command routing dict
for cmd in self.pjlink_functions:
self.pjlink_functions[cmd]["version"] = PJLINK_VALID_CMD[cmd]['default']
def process_command(self, cmd, data):
"""
@ -320,20 +276,33 @@ class PJLinkCommands(object):
return self.change_status(status=E_AUTHENTICATION)
# Command checks already passed
log.debug('({ip}) Calling function for {cmd}'.format(ip=self.entry.name, cmd=cmd))
self.pjlink_functions[cmd](data=data)
self.pjlink_functions[cmd]["method"](data=data)
def process_ackn(self, data):
"""
Process the ACKN command.
:param data: Data in packet
"""
# TODO: Have to rethink this one
pass
def process_avmt(self, data):
"""
Process shutter and speaker status. See PJLink specification for format.
Update self.mute (audio) and self.shutter (video shutter).
10 = Shutter open, audio unchanged
11 = Shutter closed, audio unchanged
20 = Shutter unchanged, Audio normal
21 = Shutter unchanged, Audio muted
30 = Shutter closed, audio muted
31 = Shutter open, audio normal
30 = Shutter open, audio muted
31 = Shutter closed, audio normal
:param data: Shutter and audio status
"""
settings = {'11': {'shutter': True, 'mute': self.mute},
settings = {'10': {'shutter': False, 'mute': self.mute},
'11': {'shutter': True, 'mute': self.mute},
'20': {'shutter': self.shutter, 'mute': False},
'21': {'shutter': self.shutter, 'mute': True},
'30': {'shutter': False, 'mute': False},
'31': {'shutter': True, 'mute': True}
@ -348,6 +317,8 @@ class PJLinkCommands(object):
self.shutter = shutter
self.mute = mute
if update_icons:
if 'AVMT' in self.status_timer_checks:
self.status_timer_delete('AVMT')
self.projectorUpdateIcons.emit()
return
@ -367,12 +338,13 @@ class PJLinkCommands(object):
# Due to stupid projectors not following standards (Optoma, BenQ comes to mind),
# AND the different responses that can be received, the semi-permanent way to
# fix the class reply is to just remove all non-digit characters.
try:
clss = re.findall('\d', data)[0] # Should only be the first match
except IndexError:
chk = re.findall(r'\d', data)
if len(chk) < 1:
log.error('({ip}) No numbers found in class version reply "{data}" - '
'defaulting to class "1"'.format(ip=self.entry.name, data=data))
clss = '1'
else:
clss = chk[0] # Should only be the first match
elif not data.isdigit():
log.error('({ip}) NAN CLSS version reply "{data}" - '
'defaulting to class "1"'.format(ip=self.entry.name, data=data))
@ -383,6 +355,11 @@ class PJLinkCommands(object):
log.debug('({ip}) Setting pjlink_class for this projector '
'to "{data}"'.format(ip=self.entry.name,
data=self.pjlink_class))
# Update method class versions
for cmd in self.pjlink_functions:
if self.pjlink_class in PJLINK_VALID_CMD[cmd]['version']:
self.pjlink_functions[cmd]['version'] = self.pjlink_class
# Since we call this one on first connect, setup polling from here
if not self.no_poll:
log.debug('({ip}) process_pjlink(): Starting timer'.format(ip=self.entry.name))
@ -542,6 +519,16 @@ class PJLinkCommands(object):
self.lamp = lamps
return
def process_lkup(self, data):
"""
Process reply indicating remote is available for connection
:param data: Data packet from remote
"""
log.debug('({ip}) Processing LKUP command'.format(ip=self.entry.name))
if Settings().value('projector/connect when LKUP received'):
self.connect_to_host()
def process_name(self, data):
"""
Projector name set in projector.
@ -615,6 +602,8 @@ class PJLinkCommands(object):
else:
# Log unknown status response
log.warning('({ip}) Unknown power response: "{data}"'.format(ip=self.entry.name, data=data))
if self.power in [S_ON, S_STANDBY, S_OFF] and 'POWR' in self.status_timer_checks:
self.status_timer_delete(cmd='POWR')
return
def process_rfil(self, data):
@ -659,6 +648,17 @@ class PJLinkCommands(object):
log.warning('({ip}) NOT saving serial number'.format(ip=self.entry.name))
self.serial_no_received = data
def process_srch(self, data):
"""
Process the SRCH command.
SRCH is processed by terminals so we ignore any packet.
:param data: Data in packet
"""
log.warning("({ip}) SRCH packet detected - ignoring".format(ip=self.entry.ip))
return
def process_sver(self, data):
"""
Software version of projector
@ -707,15 +707,18 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
args=args,
kwargs=kwargs))
super().__init__()
self.settings_section = 'projector'
self.entry = projector
self.ip = self.entry.ip
self.qhost = QtNetwork.QHostAddress(self.ip)
self.location = self.entry.location
self.mac_adx = self.entry.mac_adx
self.name = self.entry.name
self.notes = self.entry.notes
self.pin = self.entry.pin
self.port = self.entry.port
self.port = int(self.entry.port)
self.pjlink_class = PJLINK_CLASS if self.entry.pjlink_class is None else self.entry.pjlink_class
self.ackn_list = {} # Replies from online projectors (Class 2 option)
self.db_update = False # Use to check if db needs to be updated prior to exiting
# Poll time 20 seconds unless called with something else
self.poll_time = 20000 if 'poll_time' not in kwargs else kwargs['poll_time'] * 1000
@ -743,6 +746,11 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
self.socket_timer = QtCore.QTimer(self)
self.socket_timer.setInterval(self.socket_timeout)
self.socket_timer.timeout.connect(self.socket_abort)
# Timer for doing status updates for commands that change state and should update faster
self.status_timer_checks = {} # Keep track of events for the status timer
self.status_timer = QtCore.QTimer(self)
self.status_timer.setInterval(2000) # 2 second interval should be fast enough
self.status_timer.timeout.connect(self.status_timer_update)
# Socket status signals
self.connected.connect(self.check_login)
self.disconnected.connect(self.disconnect_from_host)
@ -916,7 +924,10 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
"""
Clean out extraneous stuff in the buffer.
"""
log.warning('({ip}) {message}'.format(ip=self.entry.name, message='Invalid packet' if msg is None else msg))
log.debug('({ip}) Cleaning buffer - msg = "{message}"'.format(ip=self.entry.name, message=msg))
if msg is None:
msg = 'Invalid packet'
log.warning('({ip}) {message}'.format(ip=self.entry.name, message=msg))
self.send_busy = False
trash_count = 0
while self.bytesAvailable() > 0:
@ -926,19 +937,21 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
count=trash_count))
return
@QtCore.pyqtSlot(str, str)
def get_buffer(self, data, ip):
@QtCore.pyqtSlot(QtNetwork.QHostAddress, int, str, name='udp_data') # host, port, data
def get_buffer(self, host, port, data):
"""
Get data from somewhere other than TCP socket
:param host: QHostAddress of sender
:param port: Destination port
:param data: Data to process. buffer must be formatted as a proper PJLink packet.
:param ip: Destination IP for buffer.
"""
log.debug('({ip}) get_buffer(data="{buff}" ip="{ip_in}"'.format(ip=self.entry.name, buff=data, ip_in=ip))
if ip is None:
log.debug("({ip}) get_buffer() Don't know who data is for - exiting".format(ip=self.entry.name))
return
return self.get_data(buff=data, ip=ip)
if (port == int(self.port)) and (host.isEqual(self.qhost)):
log.debug('({ip}) Received data from {host}'.format(ip=self.entry.name, host=host.toString()))
log.debug('({ip}) get_buffer(data="{buff}")'.format(ip=self.entry.name, buff=data))
return self.get_data(buff=data)
else:
log.debug('({ip}) Ignoring data for {host} - not me'.format(ip=self.entry.name, host=host.toString()))
@QtCore.pyqtSlot()
def get_socket(self):
@ -958,59 +971,73 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.entry.name))
return self.receive_data_signal()
self.socket_timer.stop()
return self.get_data(buff=read, ip=self.ip)
return self.get_data(buff=read)
def get_data(self, buff, ip=None):
def get_data(self, buff, *args, **kwargs):
"""
Process received data
:param buff: Data to process.
:param ip: (optional) Destination IP.
"""
# Since "self" is not available to options and the "ip" keyword is a "maybe I'll use in the future",
# set to default here
if ip is None:
ip = self.ip
log.debug('({ip}) get_data(ip="{ip_in}" buffer="{buff}"'.format(ip=self.entry.name, ip_in=ip, buff=buff))
log.debug('({ip}) get_data(buffer="{buff}"'.format(ip=self.entry.name, buff=buff))
ignore_class = 'ignore_class' in kwargs
# NOTE: Class2 has changed to some values being UTF-8
data_in = decode(buff, 'utf-8')
if isinstance(buff, bytes):
data_in = decode(buff, 'utf-8')
else:
data_in = buff
data = data_in.strip()
# Initial packet checks
if (len(data) < 7):
self._trash_buffer(msg='get_data(): Invalid packet - length')
return self.receive_data_signal()
elif len(data) > self.max_size:
self._trash_buffer(msg='get_data(): Invalid packet - too long')
self._trash_buffer(msg='get_data(): Invalid packet - too long ({length} bytes)'.format(length=len(data)))
return self.receive_data_signal()
elif not data.startswith(PJLINK_PREFIX):
self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')
return self.receive_data_signal()
elif '=' not in data:
elif data[6] != '=' and data[8] != '=':
# data[6] = standard command packet
# data[8] = initial PJLink connection (after mangling)
self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')
return self.receive_data_signal()
log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.entry.name, data=data))
header, data = data.split('=')
log.debug('({ip}) get_data() header="{header}" data="{data}"'.format(ip=self.entry.name,
header=header, data=data))
# At this point, the header should contain:
# "PVCCCC"
# Where:
# P = PJLINK_PREFIX
# V = PJLink class or version
# C = PJLink command
version, cmd = header[1], header[2:].upper()
log.debug('({ip}) get_data() version="{version}" cmd="{cmd}"'.format(ip=self.entry.name,
version=version, cmd=cmd))
# TODO: Below commented for now since it seems to cause issues with testing some invalid data.
# Revisit after more refactoring is finished.
'''
try:
version, cmd = header[1], header[2:].upper()
log.debug('({ip}) get_data() version="{version}" cmd="{cmd}"'.format(ip=self.entry.name,
version=version, cmd=cmd))
except ValueError as e:
self.change_status(E_INVALID_DATA)
log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.entry.name, data=data_in))
self._trash_buffer('get_data(): Expected header + command + data')
return self.receive_data_signal()
'''
if cmd not in PJLINK_VALID_CMD:
log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.entry.name,
data=cmd))
self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
self._trash_buffer('get_data(): Invalid packet - unknown command "{data}"'.format(data=cmd))
return self.receive_data_signal()
if int(self.pjlink_class) < int(version):
log.warning('({ip}) get_data(): Projector returned class reply higher '
'than projector stated class'.format(ip=self.entry.name))
elif version not in PJLINK_VALID_CMD[cmd]['version']:
self._trash_buffer(msg='get_data() Command reply version does not match a valid command version')
return self.receive_data_signal()
elif int(self.pjlink_class) < int(version):
if not ignore_class:
log.warning('({ip}) get_data(): Projector returned class reply higher '
'than projector stated class'.format(ip=self.entry.name))
self.process_command(cmd, data)
return self.receive_data_signal()
@ -1063,16 +1090,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
data=opts,
salt='' if salt is None
else ' with hash'))
cmd_ver = PJLINK_VALID_CMD[cmd]['version']
if self.pjlink_class in PJLINK_VALID_CMD[cmd]['version']:
header = PJLINK_HEADER.format(linkclass=self.pjlink_class)
elif len(cmd_ver) == 1 and (int(cmd_ver[0]) < int(self.pjlink_class)):
# Typically a class 1 only command
header = PJLINK_HEADER.format(linkclass=cmd_ver[0])
else:
# NOTE: Once we get to version 3 then think about looping
log.error('({ip}): send_command(): PJLink class check issue? Aborting'.format(ip=self.entry.name))
return
header = PJLINK_HEADER.format(linkclass=self.pjlink_functions[cmd]["version"])
out = '{salt}{header}{command} {options}{suffix}'.format(salt="" if salt is None else salt,
header=header,
command=cmd,
@ -1098,11 +1116,18 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
"""
Socket interface to send data. If data=None, then check queue.
:param data: Immediate data to send
:param data: Immediate data to send (Optional)
:param utf8: Send as UTF-8 string otherwise send as ASCII string
"""
# Funny looking data check, but it's a quick check for data=None
log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.entry.name, data=data.strip() if data else data))
if not data and not self.priority_queue and not self.send_queue:
log.debug('({ip}) _send_command(): Nothing to send - returning'.format(ip=self.entry.name))
return
log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.entry.name,
data=data.strip() if data else data))
log.debug('({ip}) _send_command(): priority_queue: {queue}'.format(ip=self.entry.name,
queue=self.priority_queue))
log.debug('({ip}) _send_command(): send_queue: {queue}'.format(ip=self.entry.name,
queue=self.send_queue))
conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.entry.name,
data=conn_state))
@ -1140,9 +1165,9 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
self.waitForBytesWritten(2000) # 2 seconds should be enough
if sent == -1:
# Network error?
log.warning('({ip}) _send_command(): -1 received - disconnecting from host'.format(ip=self.entry.name))
self.change_status(E_NETWORK,
translate('OpenLP.PJLink', 'Error while sending data to projector'))
log.warning('({ip}) _send_command(): -1 received - disconnecting from host'.format(ip=self.entry.name))
self.disconnect_from_host()
def connect_to_host(self):
@ -1155,7 +1180,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
return
self.error_status = S_OK
self.change_status(S_CONNECTING)
self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port))
self.connectToHost(self.ip, self.port)
@QtCore.pyqtSlot()
def disconnect_from_host(self, abort=False):
@ -1168,25 +1193,27 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
self.abort()
else:
log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.entry.name))
self.disconnectFromHost()
try:
self.readyRead.disconnect(self.get_socket)
except TypeError:
pass
log.debug('({ip}) disconnect_from_host() '
# Since we already know what's happening, just log it for reference.
log.debug('({ip}) disconnect_from_host(): Issue detected with '
'readyRead.disconnect'.format(ip=self.entry.name))
log.debug('({ip}) disconnect_from_host(): '
'Current status {data}'.format(ip=self.entry.name, data=self._get_status(self.status_connect)[0]))
self.disconnectFromHost()
if abort:
self.change_status(E_NOT_CONNECTED)
else:
self.change_status(S_NOT_CONNECTED)
self.reset_information()
def get_av_mute_status(self):
def get_av_mute_status(self, priority=False):
"""
Send command to retrieve shutter status.
"""
log.debug('({ip}) Sending AVMT command'.format(ip=self.entry.name))
return self.send_command(cmd='AVMT')
return self.send_command(cmd='AVMT', priority=priority)
def get_available_inputs(self):
"""
@ -1244,12 +1271,14 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
log.debug('({ip}) Sending INFO command'.format(ip=self.entry.name))
return self.send_command(cmd='INFO')
def get_power_status(self):
def get_power_status(self, priority=False):
"""
Send command to retrieve power status.
:param priority: (OPTIONAL) Send in priority queue
"""
log.debug('({ip}) Sending POWR command'.format(ip=self.entry.name))
return self.send_command(cmd='POWR')
return self.send_command(cmd='POWR', priority=priority)
def set_input_source(self, src=None):
"""
@ -1273,6 +1302,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
"""
log.debug('({ip}) Setting POWR to 1 (on)'.format(ip=self.entry.name))
self.send_command(cmd='POWR', opts='1', priority=True)
self.status_timer_add(cmd='POWR', callback=self.get_power_status)
self.poll_loop()
def set_power_off(self):
@ -1281,6 +1311,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
"""
log.debug('({ip}) Setting POWR to 0 (standby)'.format(ip=self.entry.name))
self.send_command(cmd='POWR', opts='0', priority=True)
self.status_timer_add(cmd='POWR', callback=self.get_power_status)
self.poll_loop()
def set_shutter_closed(self):
@ -1289,6 +1320,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
"""
log.debug('({ip}) Setting AVMT to 11 (shutter closed)'.format(ip=self.entry.name))
self.send_command(cmd='AVMT', opts='11', priority=True)
self.status_timer_add('AVMT', self.get_av_mute_status)
self.poll_loop()
def set_shutter_open(self):
@ -1297,8 +1329,51 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
"""
log.debug('({ip}) Setting AVMT to "10" (shutter open)'.format(ip=self.entry.name))
self.send_command(cmd='AVMT', opts='10', priority=True)
self.status_timer_add('AVMT', self.get_av_mute_status)
self.poll_loop()
self.projectorUpdateIcons.emit()
def status_timer_add(self, cmd, callback):
"""
Add a callback to the status timer.
:param cmd: PJLink command associated with callback
:param callback: Method to call
"""
if cmd in self.status_timer_checks:
log.warning('({ip}) "{cmd}" already in checks - returning'.format(ip=self.entry.name, cmd=cmd))
return
log.debug('({ip}) Adding "{cmd}" callback for status timer'.format(ip=self.entry.name, cmd=cmd))
if not self.status_timer.isActive():
self.status_timer.start()
self.status_timer_checks[cmd] = callback
def status_timer_delete(self, cmd):
"""
Delete a callback from the status timer.
:param cmd: PJLink command associated with callback
:param callback: Method to call
"""
if cmd not in self.status_timer_checks:
log.warning('({ip}) "{cmd}" not listed in status timer - returning'.format(ip=self.entry.name, cmd=cmd))
return
log.debug('({ip}) Removing "{cmd}" from status timer'.format(ip=self.entry.name, cmd=cmd))
self.status_timer_checks.pop(cmd)
if not self.status_timer_checks:
self.status_timer.stop()
def status_timer_update(self):
"""
Call methods defined in status_timer_checks for updates
"""
if not self.status_timer_checks:
log.warning('({ip}) status_timer_update() called when no callbacks - '
'Race condition?'.format(ip=self.entry.name))
self.status_timer.stop()
return
for cmd, callback in self.status_timer_checks.items():
log.debug('({ip}) Status update call for {cmd}'.format(ip=self.entry.name, cmd=cmd))
callback(priority=True)
def receive_data_signal(self):
"""

View File

@ -29,6 +29,7 @@ from PyQt5 import QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
from openlp.core.ui.icons import UiIcons
from openlp.core.projectors import DialogSourceStyle
log = logging.getLogger(__name__)
@ -45,7 +46,7 @@ class ProjectorTab(SettingsTab):
:param parent: Parent widget
"""
self.icon_path = ':/projector/projector_manager.png'
self.icon_path = UiIcons().projector
projector_translated = translate('OpenLP.ProjectorTab', 'Projector')
super(ProjectorTab, self).__init__(parent, 'Projector', projector_translated)
@ -89,6 +90,10 @@ class ProjectorTab(SettingsTab):
self.connect_box_layout.addRow(self.dialog_type_label, self.dialog_type_combo_box)
self.left_layout.addStretch()
self.dialog_type_combo_box.activated.connect(self.on_dialog_type_combo_box_changed)
# Connect on LKUP packet received (PJLink v2+ only)
self.connect_on_linkup = QtWidgets.QCheckBox(self.connect_box)
self.connect_on_linkup.setObjectName('connect_on_linkup')
self.connect_box_layout.addRow(self.connect_on_linkup)
def retranslateUi(self):
"""
@ -109,30 +114,28 @@ class ProjectorTab(SettingsTab):
translate('OpenLP.ProjectorTab', 'Tabbed dialog box'))
self.dialog_type_combo_box.setItemText(DialogSourceStyle.Single,
translate('OpenLP.ProjectorTab', 'Single dialog box'))
self.connect_on_linkup.setText(
translate('OpenLP.ProjectorTab', 'Connect to projector when LINKUP received (v2 only)'))
def load(self):
"""
Load the projector settings on startup
"""
settings = Settings()
settings.beginGroup(self.settings_section)
self.connect_on_startup.setChecked(settings.value('connect on start'))
self.socket_timeout_spin_box.setValue(settings.value('socket timeout'))
self.socket_poll_spin_box.setValue(settings.value('poll time'))
self.dialog_type_combo_box.setCurrentIndex(settings.value('source dialog type'))
settings.endGroup()
self.connect_on_startup.setChecked(Settings().value('projector/connect on start'))
self.socket_timeout_spin_box.setValue(Settings().value('projector/socket timeout'))
self.socket_poll_spin_box.setValue(Settings().value('projector/poll time'))
self.dialog_type_combo_box.setCurrentIndex(Settings().value('projector/source dialog type'))
self.connect_on_linkup.setChecked(Settings().value('projector/connect when LKUP received'))
def save(self):
"""
Save the projector settings
"""
settings = Settings()
settings.beginGroup(self.settings_section)
settings.setValue('connect on start', self.connect_on_startup.isChecked())
settings.setValue('socket timeout', self.socket_timeout_spin_box.value())
settings.setValue('poll time', self.socket_poll_spin_box.value())
settings.setValue('source dialog type', self.dialog_type_combo_box.currentIndex())
settings.endGroup()
Settings().setValue('projector/connect on start', self.connect_on_startup.isChecked())
Settings().setValue('projector/socket timeout', self.socket_timeout_spin_box.value())
Settings().setValue('projector/poll time', self.socket_poll_spin_box.value())
Settings().setValue('projector/source dialog type', self.dialog_type_combo_box.currentIndex())
Settings().setValue('projector/connect when LKUP received', self.connect_on_linkup.isChecked())
def on_dialog_type_combo_box_changed(self):
self.dialog_type = self.dialog_type_combo_box.currentIndex()

View File

@ -53,12 +53,13 @@ class Server(QtCore.QObject, LogMixin):
if 'OpenLP' in args:
args.remove('OpenLP')
# Yes, there is.
self.out_stream = QtCore.QTextStream(self.out_socket)
self.out_stream.setCodec('UTF-8')
self.out_socket.write(str.encode("".join(args)))
if not self.out_socket.waitForBytesWritten(10):
raise Exception(str(self.out_socket.errorString()))
self.out_socket.disconnectFromServer()
if len(args):
self.out_stream = QtCore.QTextStream(self.out_socket)
self.out_stream.setCodec('UTF-8')
self.out_socket.write(str.encode("".join(args)))
if not self.out_socket.waitForBytesWritten(10):
raise Exception(str(self.out_socket.errorString()))
self.out_socket.disconnectFromServer()
def start_server(self):
"""

View File

@ -123,4 +123,4 @@ __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideCon
'ServiceNoteForm', 'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay',
'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController', 'SingleColumnTableWidget',
'ProjectorManager', 'ProjectorTab', 'ProjectorEditForm']
'ProjectorManager', 'ProjectorTab', 'ProjectorEditForm', 'LiveController', 'PreviewController']

View File

@ -24,8 +24,8 @@ import datetime
from PyQt5 import QtGui, QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box
from openlp.core.ui.icons import UiIcons
class UiAboutDialog(object):
@ -40,7 +40,7 @@ class UiAboutDialog(object):
:param about_dialog: The QDialog object to set up.
"""
about_dialog.setObjectName('about_dialog')
about_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
about_dialog.setWindowIcon(UiIcons().main_icon)
self.about_dialog_layout = QtWidgets.QVBoxLayout(about_dialog)
self.about_dialog_layout.setContentsMargins(8, 8, 8, 8)
self.about_dialog_layout.setObjectName('about_dialog_layout')
@ -78,7 +78,7 @@ class UiAboutDialog(object):
self.license_tab_layout.addWidget(self.license_text_edit)
self.about_notebook.addTab(self.license_tab, '')
self.about_dialog_layout.addWidget(self.about_notebook)
self.volunteer_button = create_button(None, 'volunteer_button', icon=':/system/system_volunteer.png')
self.volunteer_button = create_button(None, 'volunteer_button', icon=UiIcons().volunteer)
self.button_box = create_button_box(about_dialog, 'button_box', ['close'], [self.volunteer_button])
self.about_dialog_layout.addWidget(self.button_box)
self.retranslate_ui(about_dialog)

View File

@ -33,8 +33,10 @@ from openlp.core.common.i18n import UiStrings, format_time, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab, build_icon
from openlp.core.ui.style import HAS_DARK_STYLE
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.edits import PathEdit
from openlp.core.widgets.enums import PathEditType
from openlp.core.widgets.widgets import ProxyWidget
log = logging.getLogger(__name__)
@ -49,7 +51,7 @@ class AdvancedTab(SettingsTab):
Initialise the settings tab
"""
self.data_exists = False
self.icon_path = ':/system/system_settings.png'
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},
@ -76,6 +78,9 @@ class AdvancedTab(SettingsTab):
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.addWidget(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)
@ -116,43 +121,8 @@ class AdvancedTab(SettingsTab):
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)
# Data Directory
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
self.data_directory_group_box.setObjectName('data_directory_group_box')
self.data_directory_layout = QtWidgets.QFormLayout(self.data_directory_group_box)
self.data_directory_layout.setObjectName('data_directory_layout')
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_new_label.setObjectName('data_directory_current_label')
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathEditType.Directories,
default_path=AppLocation.get_directory(AppLocation.DataDir))
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
self.new_data_directory_has_files_label.setWordWrap(True)
self.data_directory_cancel_button = QtWidgets.QToolButton(self.data_directory_group_box)
self.data_directory_cancel_button.setObjectName('data_directory_cancel_button')
self.data_directory_cancel_button.setIcon(build_icon(':/general/general_delete.png'))
self.data_directory_copy_check_layout = QtWidgets.QHBoxLayout()
self.data_directory_copy_check_layout.setObjectName('data_directory_copy_check_layout')
self.data_directory_copy_check_box = QtWidgets.QCheckBox(self.data_directory_group_box)
self.data_directory_copy_check_box.setObjectName('data_directory_copy_check_box')
self.data_directory_copy_check_layout.addWidget(self.data_directory_copy_check_box)
self.data_directory_copy_check_layout.addStretch()
self.data_directory_copy_check_layout.addWidget(self.data_directory_cancel_button)
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
self.left_layout.addWidget(self.data_directory_group_box)
# Hide mouse
self.hide_mouse_group_box = QtWidgets.QGroupBox(self.right_column)
self.hide_mouse_group_box.setObjectName('hide_mouse_group_box')
self.hide_mouse_layout = QtWidgets.QVBoxLayout(self.hide_mouse_group_box)
self.hide_mouse_layout.setObjectName('hide_mouse_layout')
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.hide_mouse_group_box)
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
self.hide_mouse_layout.addWidget(self.hide_mouse_check_box)
self.right_layout.addWidget(self.hide_mouse_group_box)
# Service Item Slide Limits
self.slide_group_box = QtWidgets.QGroupBox(self.right_column)
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')
@ -168,7 +138,33 @@ class AdvancedTab(SettingsTab):
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)
self.left_layout.addWidget(self.slide_group_box)
# Data Directory
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
self.data_directory_group_box.setObjectName('data_directory_group_box')
self.data_directory_layout = QtWidgets.QFormLayout(self.data_directory_group_box)
self.data_directory_layout.setObjectName('data_directory_layout')
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_new_label.setObjectName('data_directory_current_label')
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathEditType.Directories,
default_path=AppLocation.get_directory(AppLocation.DataDir))
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
self.new_data_directory_has_files_label.setWordWrap(True)
self.data_directory_cancel_button = QtWidgets.QToolButton(self.data_directory_group_box)
self.data_directory_cancel_button.setObjectName('data_directory_cancel_button')
self.data_directory_cancel_button.setIcon(UiIcons().delete)
self.data_directory_copy_check_layout = QtWidgets.QHBoxLayout()
self.data_directory_copy_check_layout.setObjectName('data_directory_copy_check_layout')
self.data_directory_copy_check_box = QtWidgets.QCheckBox(self.data_directory_group_box)
self.data_directory_copy_check_box.setObjectName('data_directory_copy_check_box')
self.data_directory_copy_check_layout.addWidget(self.data_directory_copy_check_box)
self.data_directory_copy_check_layout.addStretch()
self.data_directory_copy_check_layout.addWidget(self.data_directory_cancel_button)
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
self.left_layout.addWidget(self.data_directory_group_box)
# Display Workarounds
self.display_workaround_group_box = QtWidgets.QGroupBox(self.right_column)
self.display_workaround_group_box.setObjectName('display_workaround_group_box')
@ -211,7 +207,7 @@ class AdvancedTab(SettingsTab):
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(build_icon(':/general/general_revert.png'))
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)
@ -223,6 +219,9 @@ class AdvancedTab(SettingsTab):
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
self.proxy_widget = ProxyWidget(self.right_column)
self.right_layout.addWidget(self.proxy_widget)
# After the last item on each side, add some spacing
self.left_layout.addStretch()
self.right_layout.addStretch()
@ -311,7 +310,6 @@ class AdvancedTab(SettingsTab):
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_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor'))
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_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel'))
@ -334,6 +332,7 @@ class AdvancedTab(SettingsTab):
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()
def load(self):
"""
@ -436,6 +435,7 @@ class AdvancedTab(SettingsTab):
if HAS_DARK_STYLE:
settings.setValue('use_dark_style', self.use_dark_style_checkbox.isChecked())
settings.endGroup()
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)

View File

@ -26,7 +26,7 @@ The GUI widgets of the exception dialog.
from PyQt5 import QtGui, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
from openlp.core.lib.ui import create_button, create_button_box
@ -39,7 +39,7 @@ class Ui_ExceptionDialog(object):
Set up the UI.
"""
exception_dialog.setObjectName('exception_dialog')
exception_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
exception_dialog.setWindowIcon(UiIcons().main_icon)
self.exception_layout = QtWidgets.QVBoxLayout(exception_dialog)
self.exception_layout.setObjectName('exception_layout')
self.message_layout = QtWidgets.QHBoxLayout()
@ -48,7 +48,7 @@ class Ui_ExceptionDialog(object):
self.message_layout.setContentsMargins(0, 0, 50, 0)
self.message_layout.addSpacing(12)
self.bug_label = QtWidgets.QLabel(exception_dialog)
self.bug_label.setPixmap(QtGui.QPixmap(':/graphics/exception.png'))
self.bug_label.setPixmap(UiIcons().exception.pixmap(40, 40))
self.bug_label.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self.bug_label.setObjectName('bug_label')
self.message_layout.addWidget(self.bug_label)
@ -72,13 +72,13 @@ class Ui_ExceptionDialog(object):
self.exception_text_edit.setObjectName('exception_text_edit')
self.exception_layout.addWidget(self.exception_text_edit)
self.send_report_button = create_button(exception_dialog, 'send_report_button',
icon=':/general/general_email.png',
icon=UiIcons().email,
click=self.on_send_report_button_clicked)
self.save_report_button = create_button(exception_dialog, 'save_report_button',
icon=':/general/general_save.png',
icon=UiIcons().save,
click=self.on_save_report_button_clicked)
self.attach_tile_button = create_button(exception_dialog, 'attach_tile_button',
icon=':/general/general_open.png',
icon=UiIcons().open,
click=self.on_attach_file_button_clicked)
self.button_box = create_button_box(exception_dialog, 'button_box', ['close'],
[self.send_report_button, self.save_report_button, self.attach_tile_button])
@ -91,7 +91,7 @@ class Ui_ExceptionDialog(object):
"""
Translate the widgets on the fly.
"""
# Note that bugs mail is not clicable, but it adds the blue color and underlining and makes the test copyable.
# Note that bugs mail is not clickable, but it adds the blue color and underlining and makes the test copyable.
exception_dialog.setWindowTitle(translate('OpenLP.ExceptionDialog', 'Error Occurred'))
# Explanation text, &nbsp; adds a small space before: If possible, write in English.
self.description_explanation.setText(

View File

@ -25,8 +25,8 @@ The UI widgets for the rename dialog
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_FileRenameDialog(object):
@ -38,7 +38,7 @@ class Ui_FileRenameDialog(object):
Set up the UI
"""
file_rename_dialog.setObjectName('file_rename_dialog')
file_rename_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
file_rename_dialog.setWindowIcon(UiIcons().main_icon)
file_rename_dialog.resize(300, 10)
self.dialog_layout = QtWidgets.QGridLayout(file_rename_dialog)
self.dialog_layout.setObjectName('dialog_layout')

View File

@ -25,8 +25,8 @@ The UI widgets of the language selection dialog.
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_FirstTimeLanguageDialog(object):
@ -38,7 +38,7 @@ class Ui_FirstTimeLanguageDialog(object):
Set up the UI.
"""
language_dialog.setObjectName('language_dialog')
language_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
language_dialog.setWindowIcon(UiIcons().main_icon)
language_dialog.resize(300, 50)
self.dialog_layout = QtWidgets.QVBoxLayout(language_dialog)
self.dialog_layout.setContentsMargins(8, 8, 8, 8)

View File

@ -25,10 +25,10 @@ The UI widgets for the first time wizard.
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import is_macosx, clean_button_text
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings
from openlp.core.lib import build_icon
from openlp.core.lib.ui import add_welcome_page
from openlp.core.ui.icons import UiIcons
class FirstTimePage(object):
@ -57,7 +57,7 @@ class UiFirstTimeWizard(object):
:param first_time_wizard: The wizard form
"""
first_time_wizard.setObjectName('first_time_wizard')
first_time_wizard.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
first_time_wizard.setWindowIcon(UiIcons().main_icon)
first_time_wizard.resize(550, 386)
first_time_wizard.setModal(True)
first_time_wizard.setOptions(QtWidgets.QWizard.IndependentPages | QtWidgets.QWizard.NoBackButtonOnStartPage |

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"users": "0041",
"file-text": "0042",
"search-text": "0043",
"search-lyrcs": "0044",
"search-CCLI": "0045",
"hdmi": "0046",
"video": "0047",
"plus_sign": "0048",
"minus_sign": "0049"
}

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@ The UI widgets for the formatting tags window.
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
from openlp.core.lib.ui import create_button_box
@ -38,7 +38,7 @@ class Ui_FormattingTagDialog(object):
Set up the UI
"""
formatting_tag_dialog.setObjectName('formatting_tag_dialog')
formatting_tag_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
formatting_tag_dialog.setWindowIcon(UiIcons().main_icon)
formatting_tag_dialog.resize(725, 548)
self.list_data_grid_layout = QtWidgets.QVBoxLayout(formatting_tag_dialog)
self.list_data_grid_layout.setContentsMargins(8, 8, 8, 8)
@ -87,11 +87,11 @@ class Ui_FormattingTagDialog(object):
self.list_data_grid_layout.addWidget(self.tag_table_widget)
self.edit_button_layout = QtWidgets.QHBoxLayout()
self.new_button = QtWidgets.QPushButton(formatting_tag_dialog)
self.new_button.setIcon(build_icon(':/general/general_new.png'))
self.new_button.setIcon(UiIcons().new)
self.new_button.setObjectName('new_button')
self.edit_button_layout.addWidget(self.new_button)
self.delete_button = QtWidgets.QPushButton(formatting_tag_dialog)
self.delete_button.setIcon(build_icon(':/general/general_delete.png'))
self.delete_button.setIcon(UiIcons().delete)
self.delete_button.setObjectName('delete_button')
self.edit_button_layout.addWidget(self.delete_button)
self.edit_button_layout.addStretch()
@ -100,7 +100,7 @@ class Ui_FormattingTagDialog(object):
self.save_button = self.button_box.button(QtWidgets.QDialogButtonBox.Save)
self.save_button.setObjectName('save_button')
self.restore_button = self.button_box.button(QtWidgets.QDialogButtonBox.RestoreDefaults)
self.restore_button.setIcon(build_icon(':/general/general_revert.png'))
self.restore_button.setIcon(UiIcons().undo)
self.restore_button.setObjectName('restore_button')
self.list_data_grid_layout.addWidget(self.button_box)
self.retranslateUi(formatting_tag_dialog)

View File

@ -24,7 +24,7 @@ The general tab of the configuration dialog.
"""
import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import QtGui, QtWidgets
from openlp.core.common import get_images_filter
from openlp.core.common.i18n import UiStrings, translate
@ -62,60 +62,64 @@ class GeneralTab(SettingsTab):
super(GeneralTab, self).setupUi()
self.tab_layout.setStretch(1, 1)
# Monitors
self.monitor_group_box = QtWidgets.QGroupBox(self.left_column)
self.monitor_group_box.setObjectName('monitor_group_box')
self.monitor_layout = QtWidgets.QGridLayout(self.monitor_group_box)
self.monitor_layout.setObjectName('monitor_layout')
self.monitor_radio_button = QtWidgets.QRadioButton(self.monitor_group_box)
self.monitor_radio_button.setObjectName('monitor_radio_button')
self.monitor_layout.addWidget(self.monitor_radio_button, 0, 0, 1, 5)
self.monitor_combo_box = QtWidgets.QComboBox(self.monitor_group_box)
self.monitor_combo_box.setObjectName('monitor_combo_box')
self.monitor_layout.addWidget(self.monitor_combo_box, 1, 1, 1, 4)
self.screen_group_box = QtWidgets.QGroupBox(self.left_column)
self.screen_group_box.setObjectName('screen_group_box')
self.screen_layout = QtWidgets.QVBoxLayout(self.screen_group_box)
self.screen_layout.setObjectName('screen_layout')
self.screen_combo_box = QtWidgets.QComboBox(self.screen_group_box)
self.screen_combo_box.setObjectName('screen_combo_box')
self.screen_layout.addWidget(self.screen_combo_box)
# Actual screen details
self.screen_detail_layout = QtWidgets.QGridLayout()
self.screen_detail_layout.setContentsMargins(0, 0, 0, 0)
# self.screen_detail_layout.setSpacing(8)
self.screen_detail_layout.setObjectName('screen_detail_layout')
self.screen_use_this_checkbox = QtWidgets.QCheckBox(self.screen_group_box)
self.screen_use_this_checkbox.setObjectName('screen_use_this_checkbox')
self.screen_detail_layout.addWidget(self.screen_use_this_checkbox)
# Display Position
self.override_radio_button = QtWidgets.QRadioButton(self.monitor_group_box)
self.override_radio_button = QtWidgets.QRadioButton(self.screen_group_box)
self.override_radio_button.setObjectName('override_radio_button')
self.monitor_layout.addWidget(self.override_radio_button, 2, 0, 1, 5)
# Custom position
self.custom_x_label = QtWidgets.QLabel(self.monitor_group_box)
self.screen_detail_layout.addWidget(self.override_radio_button)
self.custom_x_label = QtWidgets.QLabel(self.screen_group_box)
self.custom_x_label.setObjectName('custom_x_label')
self.monitor_layout.addWidget(self.custom_x_label, 3, 1)
self.custom_X_value_edit = QtWidgets.QSpinBox(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_x_label, 3, 1)
self.custom_X_value_edit = QtWidgets.QSpinBox(self.screen_group_box)
self.custom_X_value_edit.setObjectName('custom_X_value_edit')
self.custom_X_value_edit.setRange(-9999, 9999)
self.monitor_layout.addWidget(self.custom_X_value_edit, 4, 1)
self.custom_y_label = QtWidgets.QLabel(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_X_value_edit, 4, 1)
self.custom_y_label = QtWidgets.QLabel(self.screen_group_box)
self.custom_y_label.setObjectName('custom_y_label')
self.monitor_layout.addWidget(self.custom_y_label, 3, 2)
self.custom_Y_value_edit = QtWidgets.QSpinBox(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_y_label, 3, 2)
self.custom_Y_value_edit = QtWidgets.QSpinBox(self.screen_group_box)
self.custom_Y_value_edit.setObjectName('custom_Y_value_edit')
self.custom_Y_value_edit.setRange(-9999, 9999)
self.monitor_layout.addWidget(self.custom_Y_value_edit, 4, 2)
self.custom_width_label = QtWidgets.QLabel(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_Y_value_edit, 4, 2)
self.custom_width_label = QtWidgets.QLabel(self.screen_group_box)
self.custom_width_label.setObjectName('custom_width_label')
self.monitor_layout.addWidget(self.custom_width_label, 3, 3)
self.custom_width_value_edit = QtWidgets.QSpinBox(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_width_label, 3, 3)
self.custom_width_value_edit = QtWidgets.QSpinBox(self.screen_group_box)
self.custom_width_value_edit.setObjectName('custom_width_value_edit')
self.custom_width_value_edit.setRange(1, 9999)
self.monitor_layout.addWidget(self.custom_width_value_edit, 4, 3)
self.custom_height_label = QtWidgets.QLabel(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_width_value_edit, 4, 3)
self.custom_height_label = QtWidgets.QLabel(self.screen_group_box)
self.custom_height_label.setObjectName('custom_height_label')
self.monitor_layout.addWidget(self.custom_height_label, 3, 4)
self.custom_height_value_edit = QtWidgets.QSpinBox(self.monitor_group_box)
self.screen_layout.addWidget(self.custom_height_label, 3, 4)
self.custom_height_value_edit = QtWidgets.QSpinBox(self.screen_group_box)
self.custom_height_value_edit.setObjectName('custom_height_value_edit')
self.custom_height_value_edit.setRange(1, 9999)
self.monitor_layout.addWidget(self.custom_height_value_edit, 4, 4)
self.display_on_monitor_check = QtWidgets.QCheckBox(self.monitor_group_box)
self.display_on_monitor_check.setObjectName('monitor_combo_box')
self.monitor_layout.addWidget(self.display_on_monitor_check, 5, 0, 1, 5)
self.screen_layout.addWidget(self.custom_height_value_edit, 4, 4)
self.display_on_screen_check = QtWidgets.QCheckBox(self.screen_group_box)
self.display_on_screen_check.setObjectName('screen_combo_box')
self.screen_layout.addWidget(self.display_on_screen_check, 5, 0, 1, 5)
# Set up the stretchiness of each column, so that the first column
# less stretchy (and therefore smaller) than the others
self.monitor_layout.setColumnStretch(0, 1)
self.monitor_layout.setColumnStretch(1, 3)
self.monitor_layout.setColumnStretch(2, 3)
self.monitor_layout.setColumnStretch(3, 3)
self.monitor_layout.setColumnStretch(4, 3)
self.left_layout.addWidget(self.monitor_group_box)
self.screen_layout.setColumnStretch(0, 1)
self.screen_layout.setColumnStretch(1, 3)
self.screen_layout.setColumnStretch(2, 3)
self.screen_layout.setColumnStretch(3, 3)
self.screen_layout.setColumnStretch(4, 3)
self.left_layout.addWidget(self.screen_group_box)
# CCLI Details
self.ccli_group_box = QtWidgets.QGroupBox(self.left_column)
self.ccli_group_box.setObjectName('ccli_group_box')
@ -222,7 +226,7 @@ class GeneralTab(SettingsTab):
self.custom_width_value_edit.valueChanged.connect(self.on_display_changed)
self.custom_Y_value_edit.valueChanged.connect(self.on_display_changed)
self.custom_X_value_edit.valueChanged.connect(self.on_display_changed)
self.monitor_combo_box.currentIndexChanged.connect(self.on_display_changed)
self.screen_combo_box.currentIndexChanged.connect(self.on_display_changed)
# Reload the tab, as the screen resolution/count may have changed.
Registry().register_function('config_screen_changed', self.load)
# Remove for now
@ -236,9 +240,10 @@ class GeneralTab(SettingsTab):
Translate the general settings tab to the currently selected language
"""
self.tab_title_visible = translate('OpenLP.GeneralTab', 'General')
self.monitor_group_box.setTitle(translate('OpenLP.GeneralTab', 'Monitors'))
self.monitor_radio_button.setText(translate('OpenLP.GeneralTab', 'Select monitor for output display:'))
self.display_on_monitor_check.setText(translate('OpenLP.GeneralTab', 'Display if a single screen'))
self.screen_group_box.setTitle(translate('OpenLP.GeneralTab', 'Monitors'))
self.screen_radio_button.setText(translate('OpenLP.GeneralTab', 'Select screen for output display:'))
self.screen_use_this_checkbox.setText(translate('OpenLP.GeneralTab', 'Use this screen as a display'))
self.display_on_screen_check.setText(translate('OpenLP.GeneralTab', 'Display if a single screen'))
self.startup_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Startup'))
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'))
@ -282,17 +287,17 @@ class GeneralTab(SettingsTab):
"""
settings = Settings()
settings.beginGroup(self.settings_section)
self.monitor_combo_box.clear()
self.screen_combo_box.clear()
for screen in self.screens:
self.monitor_combo_box.addItem(str(screen), screen.number)
monitors = settings.value('monitors')
for number, monitor in monitors.items():
if monitor['is_display']:
for item_index in range(self.monitor_combo_box.count()):
if self.monitor_combo_box.itemData(item_index) == number:
self.monitor_combo_box.setCurrentIndex(item_index)
self.screen_combo_box.addItem(str(screen), screen.number)
screens = settings.value('screens')
for number, screen in screens.items():
if screen['is_display']:
for item_index in range(self.screen_combo_box.count()):
if self.screen_combo_box.itemData(item_index) == number:
self.screen_combo_box.setCurrentIndex(item_index)
else:
self.monitor_combo_box.setCurrentIndex(0)
self.screen_combo_box.setCurrentIndex(0)
self.number_edit.setText(settings.value('ccli number'))
self.username_edit.setText(settings.value('songselect username'))
self.password_edit.setText(settings.value('songselect password'))
@ -300,7 +305,7 @@ class GeneralTab(SettingsTab):
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'))
# TODO: This is going to be a more complicated setup
# self.display_on_monitor_check.setChecked(self.screens.display)
# self.display_on_screen_check.setChecked(self.screens.display)
self.warning_check_box.setChecked(settings.value('blank warning'))
self.auto_open_check_box.setChecked(settings.value('auto open'))
self.show_splash_check_box.setChecked(settings.value('show splash'))
@ -311,7 +316,7 @@ class GeneralTab(SettingsTab):
self.check_for_updates_check_box.setChecked(settings.value('update check'))
self.auto_preview_check_box.setChecked(settings.value('auto preview'))
self.timeout_spin_box.setValue(settings.value('loop delay'))
# self.monitor_radio_button.setChecked(not settings.value('override position',))
# self.screen_radio_button.setChecked(not settings.value('override position',))
# self.override_radio_button.setChecked(settings.value('override position'))
# self.custom_X_value_edit.setValue(settings.value('x position'))
# self.custom_Y_value_edit.setValue(settings.value('y position'))
@ -320,7 +325,7 @@ class GeneralTab(SettingsTab):
self.start_paused_check_box.setChecked(settings.value('audio start paused'))
self.repeat_list_check_box.setChecked(settings.value('audio repeat list'))
settings.endGroup()
# self.monitor_combo_box.setDisabled(self.override_radio_button.isChecked())
# self.screen_combo_box.setDisabled(self.override_radio_button.isChecked())
# self.custom_X_value_edit.setEnabled(self.override_radio_button.isChecked())
# self.custom_Y_value_edit.setEnabled(self.override_radio_button.isChecked())
# self.custom_height_value_edit.setEnabled(self.override_radio_button.isChecked())
@ -333,8 +338,8 @@ class GeneralTab(SettingsTab):
"""
settings = Settings()
settings.beginGroup(self.settings_section)
# settings.setValue('monitor', self.monitor_combo_box.currentIndex())
settings.setValue('display on monitor', self.display_on_monitor_check.isChecked())
# settings.setValue('screen', self.screen_combo_box.currentIndex())
settings.setValue('display on screen', self.display_on_screen_check.isChecked())
settings.setValue('blank warning', self.warning_check_box.isChecked())
settings.setValue('auto open', self.auto_open_check_box.isChecked())
settings.setValue('show splash', self.show_splash_check_box.isChecked())
@ -369,8 +374,8 @@ class GeneralTab(SettingsTab):
# Do not continue on start up.
if not is_post_update:
return
self.screens.set_display_screen(self.monitor_combo_box.currentData())
# self.screens.display = self.display_on_monitor_check.isChecked()
self.screens.set_display_screen(self.screen_combo_box.currentData())
# self.screens.display = self.display_on_screen_check.isChecked()
# self.screens.override['size'] = QtCore.QRect(
# self.custom_X_value_edit.value(),
# self.custom_Y_value_edit.value(),
@ -392,7 +397,7 @@ class GeneralTab(SettingsTab):
:param checked: The state of the check box (boolean).
"""
self.monitor_combo_box.setDisabled(checked)
self.screen_combo_box.setDisabled(checked)
self.custom_X_value_edit.setEnabled(checked)
self.custom_Y_value_edit.setEnabled(checked)
self.custom_height_value_edit.setEnabled(checked)

191
openlp/core/ui/icons.py Normal file
View File

@ -0,0 +1,191 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2018 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; version 2 of the License. #
# #
# 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, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`languages` module provides a list of icons.
"""
import logging
import qtawesome as qta
from PyQt5 import QtGui, QtWidgets
from openlp.core.common.applocation import AppLocation
from openlp.core.lib import build_icon
log = logging.getLogger(__name__)
class UiIcons(object):
"""
Provide standard icons for objects to use.
"""
__instance__ = None
def __new__(cls):
"""
Override the default object creation method to return a single instance.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
cls.load(cls)
return cls.__instance__
def load(self):
"""
These are the font icons used in the code.
"""
font_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'ui' / 'fonts' / 'OpenLP.ttf'
charmap_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'ui' / 'fonts' / 'openlp-charmap.json'
qta.load_font('op', font_path, charmap_path)
palette = QtWidgets.QApplication.palette()
qta.set_defaults(color=palette.color(QtGui.QPalette.Active,
QtGui.QPalette.ButtonText),
color_disabled=palette.color(QtGui.QPalette.Disabled,
QtGui.QPalette.ButtonText))
icon_list = {
'active': {'icon': 'fa.child'},
'add': {'icon': 'fa.plus-circle'},
'alert': {'icon': 'fa.exclamation-triangle'},
'arrow_down': {'icon': 'fa.arrow-down'},
'arrow_left': {'icon': 'fa.arrow-left'},
'arrow_right': {'icon': 'fa.arrow-right'},
'arrow_up': {'icon': 'fa.arrow-up'},
'audio': {'icon': 'fa.file-sound-o'},
'authentication': {'icon': 'fa.exclamation-triangle', 'attr': 'red'},
'address': {'icon': 'fa.book'},
'back': {'icon': 'fa.step-backward'},
'bible': {'icon': 'fa.book'},
'blank': {'icon': 'fa.times-circle'},
'blank_theme': {'icon': 'fa.file-image-o'},
'book': {'icon': 'fa.book'},
'bottom': {'icon': 'fa.angle-double-down'},
'box': {'icon': 'fa.briefcase'},
'clapperboard': {'icon': 'fa.chess-board'},
'clock': {'icon': 'fa.clock-o'},
'clone': {'icon': 'fa.clone'},
'close': {'icon': 'fa.times-circle-o'},
'copy': {'icon': 'fa.copy'},
'copyright': {'icon': 'fa.copyright'},
'database': {'icon': 'fa.database'},
'default': {'icon': 'fa.info-circle'},
'desktop': {'icon': 'fa.desktop'},
'delete': {'icon': 'fa.trash'},
'download': {'icon': 'fa.download'},
'edit': {'icon': 'fa.edit'},
'email': {'icon': 'fa.envelope'},
'error': {'icon': 'fa.exclamation', 'attr': 'red'},
'exception': {'icon': 'fa.times-circle'},
'exit': {'icon': 'fa.sign-out'},
'group': {'icon': 'fa.object-group'},
'inactive': {'icon': 'fa.child', 'attr': 'lightGray'},
'info': {'icon': 'fa.info'},
'light_bulb': {'icon': 'fa.lightbulb-o'},
'live': {'icon': 'fa.eye'},
'manual': {'icon': 'fa.graduation-cap'},
'media': {'icon': 'fa.fax'},
'minus': {'icon': 'fa.minus'},
'music': {'icon': 'fa.music'},
'new': {'icon': 'fa.file'},
'new_group': {'icon': 'fa.folder'},
'notes': {'icon': 'fa.sticky-note'},
'open': {'icon': 'fa.folder-open'},
'optical': {'icon': 'fa.file-video-o'},
'pause': {'icon': 'fa.pause'},
'play': {'icon': 'fa.play'},
'player': {'icon': 'fa.tablet'},
'plugin_list': {'icon': 'fa.puzzle-piece'},
'plus': {'icon': 'fa.plus'},
'presentation': {'icon': 'fa.bar-chart'},
'preview': {'icon': 'fa.laptop'},
'projector': {'icon': 'op.video'},
'projector_connect': {'icon': 'fa.plug'},
'projector_cooldown': {'icon': 'fa.video-camera', 'attr': 'blue'},
'projector_disconnect': {'icon': 'fa.plug', 'attr': 'lightGray'},
'projector_error': {'icon': 'fa.video-camera', 'attr': 'red'},
'projector_hdmi': {'icon': 'op.hdmi'},
'projector_off': {'icon': 'fa.video-camera', 'attr': 'black'},
'projector_on': {'icon': 'fa.video-camera', 'attr': 'green'},
'projector_warmup': {'icon': 'fa.video-camera', 'attr': 'yellow'},
'picture': {'icon': 'fa.picture-o'},
'print': {'icon': 'fa.print'},
'remote': {'icon': 'fa.rss'},
'repeat': {'icon': 'fa.repeat'},
'save': {'icon': 'fa.save'},
'search': {'icon': 'fa.search'},
'search_ccli': {'icon': 'op.search-CCLI'},
'search_comb': {'icon': 'fa.columns'},
'search_lyrcs': {'icon': 'op.search-lyrcs'},
'search_minus': {'icon': 'fa.search-minus'},
'search_plus': {'icon': 'fa.search-plus'},
'search_ref': {'icon': 'fa.institution'},
'search_text': {'icon': 'op.search-text'},
'settings': {'icon': 'fa.cogs'},
'shortcuts': {'icon': 'fa.wrench'},
'song_usage': {'icon': 'fa.line-chart'},
'song_usage_active': {'icon': 'op.plus_sign'},
'song_usage_inactive': {'icon': 'op.minus_sign'},
'sort': {'icon': 'fa.sort'},
'stop': {'icon': 'fa.stop'},
'square': {'icon': 'fa.square'},
'text': {'icon': 'op.file-text'},
'time': {'icon': 'fa.history'},
'theme': {'icon': 'fa.paint-brush'},
'top': {'icon': 'fa.angle-double-up'},
'undo': {'icon': 'fa.undo'},
'upload': {'icon': 'fa.upload'},
'user': {'icon': 'fa.user'},
'usermo': {'icon': 'op.users'},
'users': {'icon': 'fa.users'},
'video': {'icon': 'fa.file-video-o'},
'volunteer': {'icon': 'fa.group'}
}
self.load_icons(self, icon_list)
def load_icons(self, icon_list):
"""
Load the list of icons to be processed
"""
for key in icon_list:
try:
icon = icon_list[key]['icon']
try:
attr = icon_list[key]['attr']
setattr(self, key, qta.icon(icon, color=attr))
except KeyError:
setattr(self, key, qta.icon(icon))
except Exception:
import sys
log.error("Unexpected error: %s" % sys.exc_info())
setattr(self, key, qta.icon('fa.plus-circle', color='red'))
except:
setattr(self, key, qta.icon('fa.plus-circle', color='red'))
self.main_icon = build_icon(':/icon/openlp-logo.svg')
@staticmethod
def _print_icons():
"""
Have ability to dump icons to see what is actually available. Can only run within an application
:return:
"""
ico = qta._resource['iconic']
fa = ico.charmap['fa']
for ky in fa.keys():
print(ky, fa[ky])

View File

@ -36,12 +36,13 @@ from openlp.core.common import is_win, is_macosx, add_actions
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import LanguageManager, UiStrings, translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.mixins import LogMixin, RegistryProperties
from openlp.core.common.path import Path, copyfile, create_paths
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.display.screens import ScreenList
from openlp.core.lib import PluginManager, ImageManager, PluginStatus, build_icon
from openlp.core.lib import PluginManager, ImageManager, PluginStatus
from openlp.core.lib.ui import create_action
from openlp.core.projectors.manager import ProjectorManager
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, PluginForm, ShortcutListForm, \
@ -65,7 +66,7 @@ class Ui_MainWindow(object):
Set up the user interface
"""
main_window.setObjectName('MainWindow')
main_window.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
main_window.setWindowIcon(UiIcons().main_icon)
main_window.setDockNestingEnabled(True)
if is_macosx():
main_window.setDocumentMode(True)
@ -96,11 +97,11 @@ class Ui_MainWindow(object):
self.recent_files_menu.setObjectName('recentFilesMenu')
self.file_import_menu = QtWidgets.QMenu(self.file_menu)
if not is_macosx():
self.file_import_menu.setIcon(build_icon(u':/general/general_import.png'))
self.file_import_menu.setIcon(UiIcons().download)
self.file_import_menu.setObjectName('file_import_menu')
self.file_export_menu = QtWidgets.QMenu(self.file_menu)
if not is_macosx():
self.file_export_menu.setIcon(build_icon(u':/general/general_export.png'))
self.file_export_menu.setIcon(UiIcons().upload)
self.file_export_menu.setObjectName('file_export_menu')
# View Menu
self.view_menu = QtWidgets.QMenu(self.menu_bar)
@ -133,7 +134,7 @@ class Ui_MainWindow(object):
self.status_bar.addPermanentWidget(self.default_theme_label)
# Create the MediaManager
self.media_manager_dock = OpenLPDockWidget(main_window, 'media_manager_dock',
':/system/system_mediamanager.png')
UiIcons().box)
self.media_manager_dock.setStyleSheet(get_library_stylesheet())
# Create the media toolbox
self.media_tool_box = QtWidgets.QToolBox(self.media_manager_dock)
@ -142,13 +143,13 @@ class Ui_MainWindow(object):
main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.media_manager_dock)
# Create the service manager
self.service_manager_dock = OpenLPDockWidget(main_window, 'service_manager_dock',
':/system/system_servicemanager.png')
UiIcons().live)
self.service_manager_contents = ServiceManager(self.service_manager_dock)
self.service_manager_dock.setWidget(self.service_manager_contents)
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.service_manager_dock)
# Create the theme manager
self.theme_manager_dock = OpenLPDockWidget(main_window, 'theme_manager_dock',
':/system/system_thememanager.png')
UiIcons().theme)
self.theme_manager_contents = ThemeManager(self.theme_manager_dock)
self.theme_manager_contents.setObjectName('theme_manager_contents')
self.theme_manager_dock.setWidget(self.theme_manager_contents)
@ -156,7 +157,7 @@ class Ui_MainWindow(object):
# Create the projector manager
self.projector_manager_dock = OpenLPDockWidget(parent=main_window,
name='projector_manager_dock',
icon=':/projector/projector_manager.png')
icon=UiIcons().projector)
self.projector_manager_contents = ProjectorManager(self.projector_manager_dock)
self.projector_manager_contents.setObjectName('projector_manager_contents')
self.projector_manager_dock.setWidget(self.projector_manager_contents)
@ -165,13 +166,13 @@ class Ui_MainWindow(object):
# Create the menu items
action_list = ActionList.get_instance()
action_list.add_category(UiStrings().File, CategoryOrder.standard_menu)
self.file_new_item = create_action(main_window, 'fileNewItem', icon=':/general/general_new.png',
self.file_new_item = create_action(main_window, 'fileNewItem', icon=UiIcons().new,
can_shortcuts=True, category=UiStrings().File,
triggers=self.service_manager_contents.on_new_service_clicked)
self.file_open_item = create_action(main_window, 'fileOpenItem', icon=':/general/general_open.png',
self.file_open_item = create_action(main_window, 'fileOpenItem', icon=UiIcons().open,
can_shortcuts=True, category=UiStrings().File,
triggers=self.service_manager_contents.on_load_service_clicked)
self.file_save_item = create_action(main_window, 'fileSaveItem', icon=':/general/general_save.png',
self.file_save_item = create_action(main_window, 'fileSaveItem', icon=UiIcons().save,
can_shortcuts=True, category=UiStrings().File,
triggers=self.service_manager_contents.decide_save_method)
self.file_save_as_item = create_action(main_window, 'fileSaveAsItem', can_shortcuts=True,
@ -180,7 +181,7 @@ class Ui_MainWindow(object):
self.print_service_order_item = create_action(main_window, 'printServiceItem', can_shortcuts=True,
category=UiStrings().File,
triggers=lambda x: PrintServiceForm().exec())
self.file_exit_item = create_action(main_window, 'fileExitItem', icon=':/system/system_exit.png',
self.file_exit_item = create_action(main_window, 'fileExitItem', icon=UiIcons().exit,
can_shortcuts=True,
category=UiStrings().File, triggers=main_window.close)
# Give QT Extra Hint that this is the Exit Menu Item
@ -199,22 +200,22 @@ class Ui_MainWindow(object):
can_shortcuts=False)
action_list.add_category(UiStrings().Import, CategoryOrder.standard_menu)
self.view_projector_manager_item = create_action(main_window, 'viewProjectorManagerItem',
icon=':/projector/projector_manager.png',
icon=UiIcons().projector,
checked=self.projector_manager_dock.isVisible(),
can_shortcuts=True,
category=UiStrings().View,
triggers=self.toggle_projector_manager)
self.view_media_manager_item = create_action(main_window, 'viewMediaManagerItem',
icon=':/system/system_mediamanager.png',
icon=UiIcons().box,
checked=self.media_manager_dock.isVisible(),
can_shortcuts=True,
category=UiStrings().View, triggers=self.toggle_media_manager)
self.view_theme_manager_item = create_action(main_window, 'viewThemeManagerItem', can_shortcuts=True,
icon=':/system/system_thememanager.png',
icon=UiIcons().theme,
checked=self.theme_manager_dock.isVisible(),
category=UiStrings().View, triggers=self.toggle_theme_manager)
self.view_service_manager_item = create_action(main_window, 'viewServiceManagerItem', can_shortcuts=True,
icon=':/system/system_servicemanager.png',
icon=UiIcons().live,
checked=self.service_manager_dock.isVisible(),
category=UiStrings().View, triggers=self.toggle_service_manager)
self.view_preview_panel = create_action(main_window, 'viewPreviewPanel', can_shortcuts=True,
@ -238,20 +239,20 @@ class Ui_MainWindow(object):
self.mode_default_item.setChecked(True)
action_list.add_category(UiStrings().Tools, CategoryOrder.standard_menu)
self.tools_add_tool_item = create_action(main_window,
'toolsAddToolItem', icon=':/tools/tools_add.png',
'toolsAddToolItem', icon=UiIcons().add,
category=UiStrings().Tools, can_shortcuts=True)
self.tools_open_data_folder = create_action(main_window,
'toolsOpenDataFolder', icon=':/general/general_open.png',
'toolsOpenDataFolder', icon=UiIcons().open,
category=UiStrings().Tools, can_shortcuts=True)
self.tools_first_time_wizard = create_action(main_window,
'toolsFirstTimeWizard', icon=':/general/general_revert.png',
'toolsFirstTimeWizard', icon=UiIcons().undo,
category=UiStrings().Tools, can_shortcuts=True)
self.update_theme_images = create_action(main_window,
'updateThemeImages', category=UiStrings().Tools, can_shortcuts=True)
action_list.add_category(UiStrings().Settings, CategoryOrder.standard_menu)
self.settings_plugin_list_item = create_action(main_window,
'settingsPluginListItem',
icon=':/system/settings_plugin_list.png',
icon=UiIcons().plugin_list,
can_shortcuts=True,
category=UiStrings().Settings,
triggers=self.on_plugin_item_clicked)
@ -267,14 +268,14 @@ class Ui_MainWindow(object):
language_item = create_action(main_window, key, checked=qm_list[key] == saved_language)
add_actions(self.language_group, [language_item])
self.settings_shortcuts_item = create_action(main_window, 'settingsShortcutsItem',
icon=':/system/system_configure_shortcuts.png',
icon=UiIcons().shortcuts,
category=UiStrings().Settings, can_shortcuts=True)
# Formatting Tags were also known as display tags.
self.formatting_tag_item = create_action(main_window, 'displayTagItem',
icon=':/system/tag_editor.png', category=UiStrings().Settings,
icon=UiIcons().edit, category=UiStrings().Settings,
can_shortcuts=True)
self.settings_configure_item = create_action(main_window, 'settingsConfigureItem',
icon=':/system/system_settings.png', can_shortcuts=True,
icon=UiIcons().settings, can_shortcuts=True,
category=UiStrings().Settings)
# Give QT Extra Hint that this is the Preferences Menu Item
self.settings_configure_item.setMenuRole(QtWidgets.QAction.PreferencesRole)
@ -283,7 +284,7 @@ class Ui_MainWindow(object):
self.settings_export_item = create_action(main_window, 'settingsExportItem',
category=UiStrings().Export, can_shortcuts=True)
action_list.add_category(UiStrings().Help, CategoryOrder.standard_menu)
self.about_item = create_action(main_window, 'aboutItem', icon=':/system/system_about.png',
self.about_item = create_action(main_window, 'aboutItem', icon=UiIcons().info,
can_shortcuts=True, category=UiStrings().Help,
triggers=self.on_about_item_clicked)
# Give QT Extra Hint that this is an About Menu Item
@ -292,7 +293,7 @@ class Ui_MainWindow(object):
self.local_help_file = AppLocation.get_directory(AppLocation.AppDir) / 'OpenLP.chm'
elif is_macosx():
self.local_help_file = AppLocation.get_directory(AppLocation.AppDir) / '..' / 'Resources' / 'OpenLP.help'
self.user_manual_item = create_action(main_window, 'userManualItem', icon=':/system/system_help_contents.png',
self.user_manual_item = create_action(main_window, 'userManualItem', icon=UiIcons().manual,
can_shortcuts=True, category=UiStrings().Help,
triggers=self.on_help_clicked)
self.web_site_item = create_action(main_window, 'webSiteItem', can_shortcuts=True, category=UiStrings().Help)
@ -623,7 +624,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
"""
version_text = translate('OpenLP.MainWindow', 'Version {new} of OpenLP is now available for download (you are '
'currently running version {current}). \n\nYou can download the latest version from '
'http://openlp.org/.').format(new=version, current=get_version()[u'full'])
'https://openlp.org/.').format(new=version, current=get_version()[u'full'])
QtWidgets.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Version Updated'), version_text)
def show(self):
@ -773,7 +774,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
Load the OpenLP website
"""
import webbrowser
webbrowser.open_new('http://openlp.org/')
webbrowser.open_new('https://openlp.org/')
def on_help_clicked(self):
"""
@ -784,7 +785,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(str(self.local_help_file)))
else:
import webbrowser
webbrowser.open_new('http://manual.openlp.org/')
webbrowser.open_new('https://manual.openlp.org/')
def on_about_item_clicked(self):
"""
@ -799,7 +800,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
self.plugin_form.load()
self.plugin_form.exec()
def on_tools_open_data_folder_clicked(self):
@staticmethod
def on_tools_open_data_folder_clicked():
"""
Open data folder
"""

View File

@ -80,7 +80,7 @@ def get_media_players():
"""
log.debug('get_media_players')
saved_players = Settings().value('media/players')
reg_ex = QtCore.QRegExp(".*\[(.*)\].*")
reg_ex = QtCore.QRegExp(r'.*\[(.*)\].*')
if Settings().value('media/override player') == QtCore.Qt.Checked:
if reg_ex.exactMatch(saved_players):
overridden_player = '{text}'.format(text=reg_ex.cap(1))

View File

@ -38,6 +38,7 @@ from openlp.core.common.settings import Settings
from openlp.core.lib import ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import DisplayControllerType
from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players, \
parse_optical_path
from openlp.core.ui.media.endpoint import media_endpoint
@ -283,19 +284,19 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
# Build a Media ToolBar
controller.mediabar = OpenLPToolbar(controller)
controller.mediabar.add_toolbar_action('playbackPlay', text='media_playback_play',
icon=':/slides/media_playback_start.png',
icon=UiIcons().play,
tooltip=translate('OpenLP.SlideController', 'Start playing media.'),
triggers=controller.send_to_plugins)
controller.mediabar.add_toolbar_action('playbackPause', text='media_playback_pause',
icon=':/slides/media_playback_pause.png',
icon=UiIcons().pause,
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'),
triggers=controller.send_to_plugins)
controller.mediabar.add_toolbar_action('playbackStop', text='media_playback_stop',
icon=':/slides/media_playback_stop.png',
icon=UiIcons().stop,
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
triggers=controller.send_to_plugins)
controller.mediabar.add_toolbar_action('playbackLoop', text='media_playback_loop',
icon=':/media/media_repeat.png', checked=False,
icon=UiIcons().repeat, checked=False,
tooltip=translate('OpenLP.SlideController', 'Loop playing media.'),
triggers=controller.send_to_plugins)
controller.position_label = QtWidgets.QLabel()

View File

@ -31,6 +31,7 @@ from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import create_button
from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media import get_media_players, set_media_players
from openlp.core.widgets.buttons import ColorButton
@ -56,7 +57,7 @@ class PlayerTab(SettingsTab):
"""
self.media_players = Registry().get('media_controller').media_players
self.saved_used_players = None
self.icon_path = ':/media/multimedia-player.png'
self.icon_path = UiIcons().player
player_translated = translate('OpenLP.PlayerTab', 'Players')
super(PlayerTab, self).__init__(parent, 'Players', player_translated)

View File

@ -25,8 +25,8 @@ The UI widgets of the plugin view dialog
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_PluginViewDialog(object):
@ -38,7 +38,7 @@ class Ui_PluginViewDialog(object):
Set up the UI
"""
plugin_view_dialog.setObjectName('plugin_view_dialog')
plugin_view_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
plugin_view_dialog.setWindowIcon(UiIcons().main_icon)
plugin_view_dialog.setWindowModality(QtCore.Qt.ApplicationModal)
self.plugin_layout = QtWidgets.QVBoxLayout(plugin_view_dialog)
self.plugin_layout.setObjectName('plugin_layout')

View File

@ -25,7 +25,7 @@ The UI widgets of the print service dialog.
from PyQt5 import QtCore, QtWidgets, QtPrintSupport
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.edits import SpellTextEdit
@ -50,7 +50,7 @@ class Ui_PrintServiceDialog(object):
Set up the UI
"""
print_service_dialog.setObjectName('print_service_dialog')
print_service_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
print_service_dialog.setWindowIcon(UiIcons().main_icon)
print_service_dialog.resize(664, 594)
self.main_layout = QtWidgets.QVBoxLayout(print_service_dialog)
self.main_layout.setSpacing(0)
@ -59,31 +59,31 @@ class Ui_PrintServiceDialog(object):
self.toolbar = QtWidgets.QToolBar(print_service_dialog)
self.toolbar.setIconSize(QtCore.QSize(22, 22))
self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.print_button = self.toolbar.addAction(build_icon(':/general/general_print.png'),
self.print_button = self.toolbar.addAction(UiIcons().print,
translate('OpenLP.PrintServiceForm', 'Print'))
self.options_button = QtWidgets.QToolButton(self.toolbar)
self.options_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.options_button.setIcon(build_icon(':/system/system_configure.png'))
self.options_button.setIcon(UiIcons().settings)
self.options_button.setCheckable(True)
self.toolbar.addWidget(self.options_button)
self.toolbar.addSeparator()
self.plain_copy = self.toolbar.addAction(build_icon(':/system/system_edit_copy.png'),
self.plain_copy = self.toolbar.addAction(UiIcons().clone,
translate('OpenLP.PrintServiceForm', 'Copy'))
self.html_copy = self.toolbar.addAction(build_icon(':/system/system_edit_copy.png'),
self.html_copy = self.toolbar.addAction(UiIcons().clone,
translate('OpenLP.PrintServiceForm', 'Copy as HTML'))
self.toolbar.addSeparator()
self.zoom_in_button = QtWidgets.QToolButton(self.toolbar)
self.zoom_in_button.setIcon(build_icon(':/general/general_zoom_in.png'))
self.zoom_in_button.setIcon(UiIcons().search_plus)
self.zoom_in_button.setObjectName('zoom_in_button')
self.zoom_in_button.setIconSize(QtCore.QSize(22, 22))
self.toolbar.addWidget(self.zoom_in_button)
self.zoom_out_button = QtWidgets.QToolButton(self.toolbar)
self.zoom_out_button.setIcon(build_icon(':/general/general_zoom_out.png'))
self.zoom_out_button.setIcon(UiIcons().search_minus)
self.zoom_out_button.setObjectName('zoom_out_button')
self.zoom_out_button.setIconSize(QtCore.QSize(22, 22))
self.toolbar.addWidget(self.zoom_out_button)
self.zoom_original_button = QtWidgets.QToolButton(self.toolbar)
self.zoom_original_button.setIcon(build_icon(':/general/general_zoom_original.png'))
self.zoom_original_button.setIcon(UiIcons().search)
self.zoom_original_button.setObjectName('zoom_original_button')
self.zoom_original_button.setIconSize(QtCore.QSize(22, 22))
self.toolbar.addWidget(self.zoom_original_button)

View File

@ -33,7 +33,7 @@ from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import get_text_file_string
from openlp.core.lib import get_text_file_string, image_to_byte
from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
DEFAULT_CSS = """/*
@ -184,7 +184,7 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
custom_css = DEFAULT_CSS
self._add_element('style', custom_css, html_data.head, attribute=('type', 'text/css'))
self._add_element('body', parent=html_data)
self._add_element('h1', html.escape(self.title_line_edit.text()), html_data.body, classId='serviceTitle')
self._add_element('h1', html.escape(self.title_line_edit.text()), html_data.body, class_id='serviceTitle')
for index, item in enumerate(self.service_manager.service_items):
self._add_preview_item(html_data.body, item['service_item'], index)
if not self.show_chords_check_box.isChecked():
@ -195,10 +195,10 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
spacing_span.drop_tree()
# Add the custom service notes:
if self.footer_text_edit.toPlainText():
div = self._add_element('div', parent=html_data.body, classId='customNotes')
div = self._add_element('div', parent=html_data.body, class_id='customNotes')
self._add_element(
'span', translate('OpenLP.ServiceManager', 'Custom Service Notes: '), div, classId='customNotesTitle')
self._add_element('span', html.escape(self.footer_text_edit.toPlainText()), div, classId='customNotesText')
'span', translate('OpenLP.ServiceManager', 'Custom Service Notes: '), div, class_id='customNotesTitle')
self._add_element('span', html.escape(self.footer_text_edit.toPlainText()), div, class_id='customNotesText')
self.document.setHtml(lxml.html.tostring(html_data).decode())
self.preview_widget.updatePreview()
@ -206,10 +206,11 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
"""
Add a preview item
"""
div = self._add_element('div', classId='item', parent=body)
div = self._add_element('div', class_id='item', parent=body)
# Add the title of the service item.
item_title = self._add_element('h2', parent=div, classId='itemTitle')
self._add_element('img', parent=item_title, attribute=('src', item.icon))
item_title = self._add_element('h2', parent=div, class_id='itemTitle')
img = image_to_byte(item.icon.pixmap(20, 20).toImage())
self._add_element('img', parent=item_title, attribute=('src', 'data:image/png;base64, ' + img))
self._add_element('span', '&nbsp;' + html.escape(item.get_display_title()), item_title)
if self.slide_text_check_box.isChecked():
# Add the text of the service item.
@ -218,7 +219,7 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
verse_html = None
for slide in item.get_frames():
if not verse_def or verse_def != slide['verseTag'] or verse_html == slide['printing_html']:
text_div = self._add_element('div', parent=div, classId='itemText')
text_div = self._add_element('div', parent=div, class_id='itemText')
elif 'chordspacing' not in slide['printing_html']:
self._add_element('br', parent=text_div)
self._add_element('span', slide['printing_html'], text_div)
@ -229,7 +230,7 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
div.set('class', 'item newPage')
# Add the image names of the service item.
elif item.is_image():
ol = self._add_element('ol', parent=div, classId='imageList')
ol = self._add_element('ol', parent=div, class_id='imageList')
for slide in range(len(item.get_frames())):
self._add_element('li', item.get_frame_title(slide), ol)
# add footer
@ -237,24 +238,24 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
foot_text = foot_text.partition('<br>')[2]
if foot_text:
foot_text = html.escape(foot_text.replace('<br>', '\n'))
self._add_element('div', foot_text.replace('\n', '<br>'), parent=div, classId='itemFooter')
self._add_element('div', foot_text.replace('\n', '<br>'), parent=div, class_id='itemFooter')
# Add service items' notes.
if self.notes_check_box.isChecked():
if item.notes:
p = self._add_element('div', classId='itemNotes', parent=div)
self._add_element('span', translate('OpenLP.ServiceManager', 'Notes: '), p, classId='itemNotesTitle')
self._add_element('span', html.escape(item.notes).replace('\n', '<br>'), p, classId='itemNotesText')
p = self._add_element('div', class_id='itemNotes', parent=div)
self._add_element('span', translate('OpenLP.ServiceManager', 'Notes: '), p, class_id='itemNotesTitle')
self._add_element('span', html.escape(item.notes).replace('\n', '<br>'), p, class_id='itemNotesText')
# Add play length of media files.
if item.is_media() and self.meta_data_check_box.isChecked():
tme = item.media_length
if item.end_time > 0:
tme = item.end_time - item.start_time
title = self._add_element('div', classId='media', parent=div)
title = self._add_element('div', class_id='media', parent=div)
self._add_element(
'span', translate('OpenLP.ServiceManager', 'Playing time: '), title, classId='mediaTitle')
self._add_element('span', str(datetime.timedelta(seconds=tme)), title, classId='mediaText')
'span', translate('OpenLP.ServiceManager', 'Playing time: '), title, class_id='mediaTitle')
self._add_element('span', str(datetime.timedelta(seconds=tme)), title, class_id='mediaText')
def _add_element(self, tag, text=None, parent=None, classId=None, attribute=None):
def _add_element(self, tag, text=None, parent=None, class_id=None, attribute=None):
"""
Creates a html element. If ``text`` is given, the element's text will set and if a ``parent`` is given,
the element is appended.
@ -262,7 +263,7 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
:param tag: The html tag, e. g. ``'span'``. Defaults to ``None``.
:param text: The text for the tag. Defaults to ``None``.
:param parent: The parent element. Defaults to ``None``.
:param classId: Value for the class attribute
:param class_id: Value for the class attribute
:param attribute: Tuple name/value pair to add as an optional attribute
"""
if text is not None:
@ -271,8 +272,8 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
element = lxml.html.Element(tag)
if parent is not None:
parent.append(element)
if classId is not None:
element.set('class', classId)
if class_id is not None:
element.set('class', class_id)
if attribute is not None:
element.set(attribute[0], attribute[1])
return element

View File

@ -25,8 +25,8 @@ The UI widgets for the service item edit dialog
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box, create_button
from openlp.core.ui.icons import UiIcons
class Ui_ServiceItemEditDialog(object):
@ -38,7 +38,7 @@ class Ui_ServiceItemEditDialog(object):
Set up the UI
"""
serviceItemEditDialog.setObjectName('serviceItemEditDialog')
serviceItemEditDialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
serviceItemEditDialog.setWindowIcon(UiIcons().main_icon)
self.dialog_layout = QtWidgets.QGridLayout(serviceItemEditDialog)
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
self.dialog_layout.setSpacing(8)

View File

@ -37,6 +37,7 @@ from openlp.core.common import ThemeLevel, delete_file
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, format_time, translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
from openlp.core.common.mixins import LogMixin, RegistryProperties
from openlp.core.common.path import Path, str_to_path
@ -137,14 +138,14 @@ class Ui_ServiceManager(object):
self.layout.setContentsMargins(0, 0, 0, 0)
# Create the top toolbar
self.toolbar = OpenLPToolbar(self)
self.toolbar.add_toolbar_action('newService', text=UiStrings().NewService, icon=':/general/general_new.png',
self.toolbar.add_toolbar_action('newService', text=UiStrings().NewService, icon=UiIcons().new,
tooltip=UiStrings().CreateService, triggers=self.on_new_service_clicked)
self.toolbar.add_toolbar_action('openService', text=UiStrings().OpenService,
icon=':/general/general_open.png',
icon=UiIcons().open,
tooltip=translate('OpenLP.ServiceManager', 'Load an existing service.'),
triggers=self.on_load_service_clicked)
self.toolbar.add_toolbar_action('saveService', text=UiStrings().SaveService,
icon=':/general/general_save.png',
icon=UiIcons().save,
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
triggers=self.decide_save_method)
self.toolbar.addSeparator()
@ -178,45 +179,45 @@ class Ui_ServiceManager(object):
action_list.add_category(UiStrings().Service, CategoryOrder.standard_toolbar)
self.move_top_action = self.order_toolbar.add_toolbar_action(
'moveTop',
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=':/services/service_top.png',
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=UiIcons().top,
tooltip=translate('OpenLP.ServiceManager', 'Move item to the top of the service.'),
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_top)
self.move_up_action = self.order_toolbar.add_toolbar_action(
'moveUp',
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=':/services/service_up.png',
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=UiIcons().arrow_up,
tooltip=translate('OpenLP.ServiceManager', 'Move item up one position in the service.'),
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_up)
self.move_down_action = self.order_toolbar.add_toolbar_action(
'moveDown',
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=':/services/service_down.png',
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=UiIcons().arrow_down,
tooltip=translate('OpenLP.ServiceManager', 'Move item down one position in the service.'),
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_down)
self.move_bottom_action = self.order_toolbar.add_toolbar_action(
'moveBottom',
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=':/services/service_bottom.png',
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=UiIcons().bottom,
tooltip=translate('OpenLP.ServiceManager', 'Move item to the end of the service.'),
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_end)
self.order_toolbar.addSeparator()
self.delete_action = self.order_toolbar.add_toolbar_action(
'delete', can_shortcuts=True,
text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=':/general/general_delete.png',
text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=UiIcons().delete,
tooltip=translate('OpenLP.ServiceManager', 'Delete the selected item from the service.'),
triggers=self.on_delete_from_service)
self.order_toolbar.addSeparator()
self.expand_action = self.order_toolbar.add_toolbar_action(
'expand', can_shortcuts=True,
text=translate('OpenLP.ServiceManager', '&Expand all'), icon=':/services/service_expand_all.png',
text=translate('OpenLP.ServiceManager', '&Expand all'), icon=UiIcons().plus,
tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'),
category=UiStrings().Service, triggers=self.on_expand_all)
self.collapse_action = self.order_toolbar.add_toolbar_action(
'collapse', can_shortcuts=True,
text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=':/services/service_collapse_all.png',
text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=UiIcons().minus,
tooltip=translate('OpenLP.ServiceManager', 'Collapse all the service items.'),
category=UiStrings().Service, triggers=self.on_collapse_all)
self.order_toolbar.addSeparator()
self.make_live_action = self.order_toolbar.add_toolbar_action(
'make_live', can_shortcuts=True,
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=':/general/general_live.png',
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=UiIcons().live,
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'),
category=UiStrings().Service,
triggers=self.on_make_live_action_triggered)
@ -233,33 +234,33 @@ class Ui_ServiceManager(object):
# build the drag and drop context menu
self.dnd_menu = QtWidgets.QMenu()
self.new_action = self.dnd_menu.addAction(translate('OpenLP.ServiceManager', '&Add New Item'))
self.new_action.setIcon(build_icon(':/general/general_edit.png'))
self.new_action.setIcon(UiIcons().edit)
self.add_to_action = self.dnd_menu.addAction(translate('OpenLP.ServiceManager', '&Add to Selected Item'))
self.add_to_action.setIcon(build_icon(':/general/general_edit.png'))
self.add_to_action.setIcon(UiIcons().edit)
# build the context menu
self.menu = QtWidgets.QMenu()
self.edit_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Edit Item'),
icon=':/general/general_edit.png', triggers=self.remote_edit)
icon=UiIcons().edit, triggers=self.remote_edit)
self.rename_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Rename...'),
icon=':/general/general_edit.png',
icon=UiIcons().edit,
triggers=self.on_service_item_rename)
self.maintain_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Reorder Item'),
icon=':/general/general_edit.png',
icon=UiIcons().edit,
triggers=self.on_service_item_edit_form)
self.notes_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Notes'),
icon=':/services/service_notes.png',
icon=UiIcons().notes,
triggers=self.on_service_item_note_form)
self.time_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Start Time'),
icon=':/media/media_time.png', triggers=self.on_start_time_form)
icon=UiIcons().time, triggers=self.on_start_time_form)
self.auto_start_action = create_widget_action(self.menu, text='',
icon=':/media/auto-start_active.png',
icon=UiIcons().active,
triggers=self.on_auto_start)
# Add already existing delete action to the menu.
self.menu.addAction(self.delete_action)
self.create_custom_action = create_widget_action(self.menu,
text=translate('OpenLP.ServiceManager', 'Create New &Custom '
'Slide'),
icon=':/general/general_edit.png',
icon=UiIcons().clone,
triggers=self.create_custom)
self.menu.addSeparator()
# Add AutoPlay menu actions
@ -284,7 +285,7 @@ class Ui_ServiceManager(object):
triggers=self.on_timed_slide_interval)
self.menu.addSeparator()
self.preview_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'),
icon=':/general/general_preview.png', triggers=self.make_preview)
icon=UiIcons().preview, triggers=self.make_preview)
# Add already existing make live action to the menu.
self.menu.addAction(self.make_live_action)
self.menu.addSeparator()
@ -314,8 +315,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
Sets up the service manager, toolbars, list view, et al.
"""
super().__init__(parent)
self.active = build_icon(':/media/auto-start_active.png')
self.inactive = build_icon(':/media/auto-start_inactive.png')
self.service_items = []
self.suffixes = []
self.drop_position = -1
@ -800,11 +799,12 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
self.time_action.setVisible(True)
if service_item['service_item'].is_capable(ItemCapabilities.CanAutoStartForLive):
self.auto_start_action.setVisible(True)
self.auto_start_action.setIcon(self.inactive)
self.auto_start_action.setText(translate('OpenLP.ServiceManager', '&Auto Start - inactive'))
if service_item['service_item'].will_auto_start:
self.auto_start_action.setText(translate('OpenLP.ServiceManager', '&Auto Start - active'))
self.auto_start_action.setIcon(self.active)
self.auto_start_action.setIcon(UiIcons().active)
else:
self.auto_start_action.setIcon(UiIcons().inactive)
self.auto_start_action.setText(translate('OpenLP.ServiceManager', '&Auto Start - inactive'))
if service_item['service_item'].is_text():
for plugin in self.plugin_manager.plugins:
if plugin.name == 'custom' and plugin.status == PluginStatus.Active:
@ -1169,27 +1169,27 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
tree_widget_item = QtWidgets.QTreeWidgetItem(self.service_manager_list)
if service_item_from_item.is_valid:
if service_item_from_item.notes:
icon = QtGui.QImage(service_item_from_item.icon)
icon = service_item_from_item.icon.pixmap(80, 80).toImage()
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
overlay = QtGui.QImage(':/services/service_item_notes.png')
overlay = overlay.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
overlay = UiIcons().notes.pixmap(40, 40).toImage()
overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(icon)
painter.drawImage(0, 0, overlay)
painter.end()
tree_widget_item.setIcon(0, build_icon(icon))
elif service_item_from_item.temporary_edit:
icon = QtGui.QImage(service_item_from_item.icon)
icon = service_item_from_item.icon.pixmap(80, 80).toImage()
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
overlay = QtGui.QImage(':/general/general_export.png')
overlay = QtGui.QImage(UiIcons().upload)
overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(icon)
painter.drawImage(40, 0, overlay)
painter.end()
tree_widget_item.setIcon(0, build_icon(icon))
else:
tree_widget_item.setIcon(0, service_item_from_item.iconic_representation)
tree_widget_item.setIcon(0, service_item_from_item.icon)
else:
tree_widget_item.setIcon(0, build_icon(':/general/general_delete.png'))
tree_widget_item.setIcon(0, UiIcons().delete)
tree_widget_item.setText(0, service_item_from_item.get_display_title())
tips = []
if service_item_from_item.temporary_edit:

View File

@ -25,8 +25,8 @@ The UI widgets of the settings dialog.
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_SettingsDialog(object):
@ -38,7 +38,7 @@ class Ui_SettingsDialog(object):
Set up the UI
"""
settings_dialog.setObjectName('settings_dialog')
settings_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
settings_dialog.setWindowIcon(UiIcons().main_icon)
settings_dialog.resize(920, 625)
self.dialog_layout = QtWidgets.QGridLayout(settings_dialog)
self.dialog_layout.setObjectName('dialog_layout')

View File

@ -25,8 +25,8 @@ The list of shortcuts within a dialog.
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class CaptureShortcutButton(QtWidgets.QPushButton):
@ -72,7 +72,7 @@ class Ui_ShortcutListDialog(object):
Set up the UI
"""
shortcutListDialog.setObjectName('shortcutListDialog')
shortcutListDialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
shortcutListDialog.setWindowIcon(UiIcons().main_icon)
shortcutListDialog.resize(500, 438)
self.shortcut_list_layout = QtWidgets.QVBoxLayout(shortcutListDialog)
self.shortcut_list_layout.setObjectName('shortcut_list_layout')
@ -101,23 +101,23 @@ class Ui_ShortcutListDialog(object):
self.primary_push_button = CaptureShortcutButton(shortcutListDialog)
self.primary_push_button.setObjectName('primary_push_button')
self.primary_push_button.setMinimumSize(QtCore.QSize(84, 0))
self.primary_push_button.setIcon(build_icon(':/system/system_configure_shortcuts.png'))
self.primary_push_button.setIcon(UiIcons.shortcuts)
self.primary_layout.addWidget(self.primary_push_button)
self.clear_primary_button = QtWidgets.QToolButton(shortcutListDialog)
self.clear_primary_button.setObjectName('clear_primary_button')
self.clear_primary_button.setMinimumSize(QtCore.QSize(0, 16))
self.clear_primary_button.setIcon(build_icon(':/system/clear_shortcut.png'))
self.clear_primary_button.setIcon(UiIcons().settings)
self.primary_layout.addWidget(self.clear_primary_button)
self.details_layout.addLayout(self.primary_layout, 1, 1, 1, 1)
self.alternate_layout = QtWidgets.QHBoxLayout()
self.alternate_layout.setObjectName('alternate_layout')
self.alternate_push_button = CaptureShortcutButton(shortcutListDialog)
self.alternate_push_button.setObjectName('alternate_push_button')
self.alternate_push_button.setIcon(build_icon(':/system/system_configure_shortcuts.png'))
self.alternate_push_button.setIcon(UiIcons().settings)
self.alternate_layout.addWidget(self.alternate_push_button)
self.clear_alternate_button = QtWidgets.QToolButton(shortcutListDialog)
self.clear_alternate_button.setObjectName('clear_alternate_button')
self.clear_alternate_button.setIcon(build_icon(':/system/clear_shortcut.png'))
self.clear_alternate_button.setIcon(UiIcons().settings)
self.alternate_layout.addWidget(self.clear_alternate_button)
self.details_layout.addLayout(self.alternate_layout, 1, 2, 1, 1)
self.primary_label = QtWidgets.QLabel(shortcutListDialog)

View File

@ -38,6 +38,7 @@ from openlp.core.display.screens import ScreenList
from openlp.core.lib import ItemCapabilities, ImageSource, ServiceItemAction, build_icon
from openlp.core.lib.ui import create_action
from openlp.core.ui import HideMode, DisplayControllerType
from openlp.core.ui.icons import UiIcons
from openlp.core.display.window import DisplayWindow
from openlp.core.widgets.layouts import AspectRatioLayout
from openlp.core.widgets.toolbar import OpenLPToolbar
@ -211,14 +212,14 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.toolbar.setSizePolicy(size_toolbar_policy)
self.previous_item = create_action(self, 'previousItem_' + self.type_prefix,
text=translate('OpenLP.SlideController', 'Previous Slide'),
icon=':/slides/slide_previous.png',
icon=UiIcons().arrow_left,
tooltip=translate('OpenLP.SlideController', 'Move to previous.'),
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.on_slide_selected_previous)
self.toolbar.addAction(self.previous_item)
self.next_item = create_action(self, 'nextItem_' + self.type_prefix,
text=translate('OpenLP.SlideController', 'Next Slide'),
icon=':/slides/slide_next.png',
icon=UiIcons().arrow_right,
tooltip=translate('OpenLP.SlideController', 'Move to next.'),
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.on_slide_selected_next_action)
@ -234,28 +235,28 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.hide_menu.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
self.hide_menu.setMenu(QtWidgets.QMenu(translate('OpenLP.SlideController', 'Hide'), self.toolbar))
self.toolbar.add_toolbar_widget(self.hide_menu)
self.toolbar.add_toolbar_action('goPreview', icon=':/general/general_live.png',
self.toolbar.add_toolbar_action('goPreview', icon=UiIcons().live,
tooltip=translate('OpenLP.SlideController', 'Move to preview.'),
triggers=self.on_go_preview)
# The order of the blank to modes in Shortcuts list comes from here.
self.desktop_screen_enable = create_action(self, 'desktopScreenEnable',
text=translate('OpenLP.SlideController', 'Show Desktop'),
icon=':/slides/slide_desktop.png', can_shortcuts=True,
icon=UiIcons().desktop, can_shortcuts=True,
context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.on_hide_display_enable)
self.desktop_screen = create_action(self, 'desktopScreen',
text=translate('OpenLP.SlideController', 'Toggle Desktop'),
icon=':/slides/slide_desktop.png',
icon=UiIcons().desktop,
checked=False, can_shortcuts=True, category=self.category,
triggers=self.on_hide_display)
self.theme_screen = create_action(self, 'themeScreen',
text=translate('OpenLP.SlideController', 'Toggle Blank to Theme'),
icon=':/slides/slide_theme.png',
icon=UiIcons().blank_theme,
checked=False, can_shortcuts=True, category=self.category,
triggers=self.on_theme_display)
self.blank_screen = create_action(self, 'blankScreen',
text=translate('OpenLP.SlideController', 'Toggle Blank Screen'),
icon=':/slides/slide_blank.png',
icon=UiIcons().blank,
checked=False, can_shortcuts=True, category=self.category,
triggers=self.on_blank_display)
self.hide_menu.setDefaultAction(self.blank_screen)
@ -286,10 +287,10 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.toolbar))
self.toolbar.add_toolbar_widget(self.play_slides_menu)
self.play_slides_loop = create_action(self, 'playSlidesLoop', text=UiStrings().PlaySlidesInLoop,
icon=':/media/media_time.png', checked=False, can_shortcuts=True,
icon=UiIcons().clock, checked=False, can_shortcuts=True,
category=self.category, triggers=self.on_play_slides_loop)
self.play_slides_once = create_action(self, 'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
icon=':/media/media_time.png', checked=False, can_shortcuts=True,
icon=UiIcons().clock, checked=False, can_shortcuts=True,
category=self.category, triggers=self.on_play_slides_once)
if Settings().value(self.main_window.advanced_settings_section + '/slide limits') == SlideLimits.Wrap:
self.play_slides_menu.setDefaultAction(self.play_slides_loop)
@ -306,18 +307,18 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.receive_spin_delay()
self.toolbar.add_toolbar_widget(self.delay_spin_box)
else:
self.toolbar.add_toolbar_action('goLive', icon=':/general/general_live.png',
self.toolbar.add_toolbar_action('goLive', icon=UiIcons().live,
tooltip=translate('OpenLP.SlideController', 'Move to live.'),
triggers=self.on_go_live)
self.toolbar.add_toolbar_action('addToService', icon=':/general/general_add.png',
self.toolbar.add_toolbar_action('addToService', icon=UiIcons().add,
tooltip=translate('OpenLP.SlideController', 'Add to Service.'),
triggers=self.on_preview_add_to_service)
self.toolbar.addSeparator()
self.toolbar.add_toolbar_action('editSong', icon=':/general/general_edit.png',
self.toolbar.add_toolbar_action('editSong', icon=UiIcons().edit,
tooltip=translate('OpenLP.SlideController',
'Edit and reload song preview.'),
triggers=self.on_edit_song)
self.toolbar.add_toolbar_action('clear', icon=':/general/general_delete.png',
self.toolbar.add_toolbar_action('clear', icon=UiIcons().delete,
tooltip=translate('OpenLP.SlideController',
'Clear'),
triggers=self.on_clear)
@ -336,7 +337,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
# FIXME: object name should be changed. But this requires that we migrate the shortcut.
self.audio_pause_item = self.toolbar.add_toolbar_action(
'audioPauseItem',
icon=':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'),
icon=UiIcons().pause, text=translate('OpenLP.SlideController', 'Pause Audio'),
tooltip=translate('OpenLP.SlideController', 'Pause audio.'),
checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut,
can_shortcuts=True, triggers=self.set_audio_pause_clicked)
@ -345,7 +346,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.audio_pause_item.setParent(self.toolbar)
self.toolbar.widgetForAction(self.audio_pause_item).setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
self.next_track_item = create_action(self, 'nextTrackItem', text=UiStrings().NextTrack,
icon=':/slides/media_playback_next.png',
icon=UiIcons().arrow_right,
tooltip=translate('OpenLP.SlideController',
'Go to next audio track.'),
category=self.category,
@ -680,10 +681,10 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.toolbar.set_widget_visible('song_menu', False)
# Reset the button
self.play_slides_once.setChecked(False)
self.play_slides_once.setIcon(build_icon(':/media/media_time.png'))
self.play_slides_once.setIcon(UiIcons().clock)
self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)
self.play_slides_loop.setChecked(False)
self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
self.play_slides_loop.setIcon(UiIcons().clock)
self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)
if item.is_text():
if (Settings().value(self.main_window.songs_settings_section + '/display songbar') and
@ -1096,7 +1097,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
# done by the thread holding the lock. If it is a "start" slide, we must wait for the lock, but only for 0.2
# seconds, since we don't want to cause a deadlock
timeout = 0.2 if start else -1
if not self.slide_selected_lock.acquire(start, timeout):
if not self.slide_selected_lock.acquire(start, timeout): # pylint: disable=too-many-function-args
if start:
self.log_debug('Could not get lock in slide_selected after waiting %f, skip to avoid deadlock.'
% timeout)
@ -1286,16 +1287,16 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.play_slides_loop.setChecked(checked)
self.log_debug('on_play_slides_loop {text}'.format(text=checked))
if checked:
self.play_slides_loop.setIcon(build_icon(':/media/media_stop.png'))
self.play_slides_loop.setIcon(UiIcons().stop)
self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop)
self.play_slides_once.setIcon(build_icon(':/media/media_time.png'))
self.play_slides_once.setIcon(UiIcons().clock)
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.setIcon(UiIcons().clock)
self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)
self.on_toggle_loop()
@ -1311,16 +1312,16 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.play_slides_once.setChecked(checked)
self.log_debug('on_play_slides_once {text}'.format(text=checked))
if checked:
self.play_slides_once.setIcon(build_icon(':/media/media_stop.png'))
self.play_slides_once.setIcon(UiIcons().stop)
self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd)
self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
self.play_slides_loop.setIcon(UiIcons().clock)
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.setIcon(UiIcons().clock)
self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)
self.on_toggle_loop()

View File

@ -25,8 +25,8 @@ The UI widgets for the time dialog
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_StartTimeDialog(object):
@ -38,7 +38,7 @@ class Ui_StartTimeDialog(object):
Set up the UI
"""
StartTimeDialog.setObjectName('StartTimeDialog')
StartTimeDialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
StartTimeDialog.setWindowIcon(UiIcons().main_icon)
StartTimeDialog.resize(350, 10)
self.dialog_layout = QtWidgets.QGridLayout(StartTimeDialog)
self.dialog_layout.setObjectName('dialog_layout')

View File

@ -25,8 +25,8 @@ The layout of the theme
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_ThemeLayoutDialog(object):
@ -38,7 +38,7 @@ class Ui_ThemeLayoutDialog(object):
Set up the UI
"""
themeLayoutDialog.setObjectName('themeLayoutDialogDialog')
themeLayoutDialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
themeLayoutDialog.setWindowIcon(UiIcons().main_icon)
self.preview_layout = QtWidgets.QVBoxLayout(themeLayoutDialog)
self.preview_layout.setObjectName('preview_layout')
self.preview_area = QtWidgets.QWidget(themeLayoutDialog)

View File

@ -31,6 +31,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import delete_file
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, translate, get_locale_key
from openlp.core.ui.icons import UiIcons
from openlp.core.common.mixins import LogMixin, RegistryProperties
from openlp.core.common.path import Path, copyfile, create_paths, path_to_str
from openlp.core.common.registry import Registry, RegistryBase
@ -61,30 +62,30 @@ class Ui_ThemeManager(object):
self.toolbar = OpenLPToolbar(widget)
self.toolbar.setObjectName('toolbar')
self.toolbar.add_toolbar_action('newTheme',
text=UiStrings().NewTheme, icon=':/themes/theme_new.png',
text=UiStrings().NewTheme, icon=UiIcons().new,
tooltip=translate('OpenLP.ThemeManager', 'Create a new theme.'),
triggers=self.on_add_theme)
self.toolbar.add_toolbar_action('editTheme',
text=translate('OpenLP.ThemeManager', 'Edit Theme'),
icon=':/themes/theme_edit.png',
icon=UiIcons().edit,
tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'),
triggers=self.on_edit_theme)
self.delete_toolbar_action = self.toolbar.add_toolbar_action('delete_theme',
text=translate('OpenLP.ThemeManager',
'Delete Theme'),
icon=':/general/general_delete.png',
icon=UiIcons().delete,
tooltip=translate('OpenLP.ThemeManager',
'Delete a theme.'),
triggers=self.on_delete_theme)
self.toolbar.addSeparator()
self.toolbar.add_toolbar_action('importTheme',
text=translate('OpenLP.ThemeManager', 'Import Theme'),
icon=':/general/general_import.png',
icon=UiIcons().download,
tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'),
triggers=self.on_import_theme)
self.toolbar.add_toolbar_action('exportTheme',
text=translate('OpenLP.ThemeManager', 'Export Theme'),
icon=':/general/general_export.png',
icon=UiIcons().upload,
tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'),
triggers=self.on_export_theme)
self.layout.addWidget(self.toolbar)
@ -102,24 +103,24 @@ class Ui_ThemeManager(object):
self.menu = QtWidgets.QMenu()
self.edit_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Edit Theme'),
icon=':/themes/theme_edit.png', triggers=self.on_edit_theme)
icon=UiIcons().edit, triggers=self.on_edit_theme)
self.copy_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Copy Theme'),
icon=':/themes/theme_edit.png', triggers=self.on_copy_theme)
icon=UiIcons().copy, triggers=self.on_copy_theme)
self.rename_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Rename Theme'),
icon=':/themes/theme_edit.png', triggers=self.on_rename_theme)
icon=UiIcons().edit, triggers=self.on_rename_theme)
self.delete_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Delete Theme'),
icon=':/general/general_delete.png', triggers=self.on_delete_theme)
icon=UiIcons().delete, triggers=self.on_delete_theme)
self.menu.addSeparator()
self.global_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', 'Set As &Global Default'),
icon=':/general/general_export.png',
icon=UiIcons().default,
triggers=self.change_global_from_screen)
self.export_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Export Theme'),
icon=':/general/general_export.png', triggers=self.on_export_theme)
icon=UiIcons().upload, triggers=self.on_export_theme)
# Signals
self.theme_list_widget.doubleClicked.connect(self.change_global_from_screen)
self.theme_list_widget.currentItemChanged.connect(self.check_list_state)

View File

@ -30,6 +30,7 @@ from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import find_and_set_in_combo_box
from openlp.core.ui.icons import UiIcons
class ThemesTab(SettingsTab):
@ -40,7 +41,7 @@ class ThemesTab(SettingsTab):
"""
Constructor
"""
self.icon_path = ':/themes/theme_new.png'
self.icon_path = UiIcons().theme
theme_translated = translate('OpenLP.ThemesTab', 'Themes')
super(ThemesTab, self).__init__(parent, 'Themes', theme_translated)

View File

@ -26,9 +26,9 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import is_macosx
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.buttons import ColorButton
from openlp.core.widgets.edits import PathEdit
@ -42,7 +42,7 @@ class Ui_ThemeWizard(object):
Set up the UI
"""
theme_wizard.setObjectName('OpenLP.ThemeWizard')
theme_wizard.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
theme_wizard.setWindowIcon(UiIcons().main_icon)
theme_wizard.setModal(True)
theme_wizard.setOptions(QtWidgets.QWizard.IndependentPages |
QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.HaveCustomButton1)

View File

@ -103,7 +103,8 @@ class VersionWorker(ThreadWorker):
while retries < 3:
try:
response = requests.get(download_url, headers=headers)
remote_version = response.text.strip()
if response.status_code == 200:
remote_version = response.text.strip()
log.debug('New version found: %s', remote_version)
break
except OSError:
@ -155,7 +156,7 @@ def get_version():
full_version = file_path.read_text().rstrip()
except OSError:
log.exception('Error in version file.')
full_version = '0.0.0-bzr000'
full_version = '0.0.0'
bits = full_version.split('-')
APPLICATION_VERSION = {
'full': full_version,

View File

@ -49,7 +49,7 @@ class ColorButton(QtWidgets.QPushButton):
"""
Sets the _color variable and the background color.
:param color: String representation of a hexidecimal color
:param color: String representation of a hexadecimal color
"""
self._color = color
self.setStyleSheet('background-color: %s' % color)
@ -59,7 +59,7 @@ class ColorButton(QtWidgets.QPushButton):
"""
Property method to return the color variable
:return: String representation of a hexidecimal color
:return: String representation of a hexadecimal color
"""
return self._color
@ -68,7 +68,7 @@ class ColorButton(QtWidgets.QPushButton):
"""
Property setter to change the instance color
:param color: String representation of a hexidecimal color
:param color: String representation of a hexadecimal color
"""
self.change_color(color)

View File

@ -33,6 +33,7 @@ from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.common.settings import Settings
from openlp.core.lib import FormattingTags, build_icon
from openlp.core.lib.ui import create_widget_action, create_action
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.dialogs import FileDialog
from openlp.core.widgets.enums import PathEditType
@ -62,7 +63,7 @@ class SearchEdit(QtWidgets.QLineEdit):
self.settings_section = settings_section
self._current_search_type = -1
self.clear_button = QtWidgets.QToolButton(self)
self.clear_button.setIcon(build_icon(':/system/clear_shortcut.png'))
self.clear_button.setIcon(UiIcons().shortcuts)
self.clear_button.setCursor(QtCore.Qt.ArrowCursor)
self.clear_button.setStyleSheet('QToolButton { border: none; padding: 0px; }')
self.clear_button.resize(18, 18)
@ -150,7 +151,7 @@ class SearchEdit(QtWidgets.QLineEdit):
action.placeholder_text = placeholder
if not hasattr(self, 'menu_button'):
self.menu_button = QtWidgets.QToolButton(self)
self.menu_button.setIcon(build_icon(':/system/clear_shortcut.png'))
self.menu_button.setIcon(UiIcons().shortcuts)
self.menu_button.setCursor(QtCore.Qt.ArrowCursor)
self.menu_button.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.menu_button.setStyleSheet('QToolButton { border: none; padding: 0px 10px 0px 0px; }')
@ -229,10 +230,10 @@ class PathEdit(QtWidgets.QWidget):
self.line_edit = QtWidgets.QLineEdit(self)
widget_layout.addWidget(self.line_edit)
self.browse_button = QtWidgets.QToolButton(self)
self.browse_button.setIcon(build_icon(':/general/general_open.png'))
self.browse_button.setIcon(UiIcons().open)
widget_layout.addWidget(self.browse_button)
self.revert_button = QtWidgets.QToolButton(self)
self.revert_button.setIcon(build_icon(':/general/general_revert.png'))
self.revert_button.setIcon(UiIcons().undo)
self.revert_button.setVisible(show_revert)
widget_layout.addWidget(self.revert_button)
self.setLayout(widget_layout)

View File

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2018 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; version 2 of the License. #
# #
# 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, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.widgets.widgets` module contains custom widgets used in OpenLP
"""
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.common.settings import ProxyMode, Settings
class ProxyWidget(QtWidgets.QGroupBox):
"""
A proxy settings widget that implements loading and saving its settings.
"""
def __init__(self, parent=None):
"""
Initialise the widget.
:param QtWidgets.QWidget | None parent: The widgets parent
"""
super().__init__(parent)
self._setup()
def _setup(self):
"""
A setup method seperate from __init__ to allow easier testing
"""
self.setup_ui()
self.load()
def setup_ui(self):
"""
Create the widget layout and sub widgets
"""
self.layout = QtWidgets.QFormLayout(self)
self.radio_group = QtWidgets.QButtonGroup(self)
self.no_proxy_radio = QtWidgets.QRadioButton('', self)
self.radio_group.addButton(self.no_proxy_radio, ProxyMode.NO_PROXY)
self.layout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.no_proxy_radio)
self.use_sysem_proxy_radio = QtWidgets.QRadioButton('', self)
self.radio_group.addButton(self.use_sysem_proxy_radio, ProxyMode.SYSTEM_PROXY)
self.layout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.use_sysem_proxy_radio)
self.manual_proxy_radio = QtWidgets.QRadioButton('', self)
self.radio_group.addButton(self.manual_proxy_radio, ProxyMode.MANUAL_PROXY)
self.layout.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.manual_proxy_radio)
self.http_edit = QtWidgets.QLineEdit(self)
self.layout.addRow('HTTP:', self.http_edit)
self.https_edit = QtWidgets.QLineEdit(self)
self.layout.addRow('HTTPS:', self.https_edit)
self.username_edit = QtWidgets.QLineEdit(self)
self.layout.addRow('Username:', self.username_edit)
self.password_edit = QtWidgets.QLineEdit(self)
self.password_edit.setEchoMode(QtWidgets.QLineEdit.Password)
self.layout.addRow('Password:', self.password_edit)
# Signal / Slots
self.radio_group.buttonToggled.connect(self.on_radio_group_button_toggled)
def on_radio_group_button_toggled(self, button, checked):
"""
Handles the toggled signal on the radio buttons. The signal is emitted twice if a radio butting being toggled on
causes another radio button in the group to be toggled off.
En/Disables the `Manual Proxy` line edits depending on the currently selected radio button
:param QtWidgets.QRadioButton button: The button that has toggled
:param bool checked: The buttons new state
"""
id = self.radio_group.id(button) # The work around (see above comment)
enable_manual_edits = id == ProxyMode.MANUAL_PROXY and checked
self.http_edit.setEnabled(enable_manual_edits)
self.https_edit.setEnabled(enable_manual_edits)
self.username_edit.setEnabled(enable_manual_edits)
self.password_edit.setEnabled(enable_manual_edits)
def retranslate_ui(self):
"""
Translate the Ui
"""
self.setTitle(translate('OpenLP.ProxyWidget', 'Proxy Server Settings'))
self.no_proxy_radio.setText(translate('OpenLP.ProxyWidget', 'No prox&y'))
self.use_sysem_proxy_radio.setText(translate('OpenLP.ProxyWidget', '&Use system proxy'))
self.manual_proxy_radio.setText(translate('OpenLP.ProxyWidget', '&Manual proxy configuration'))
proxy_example = translate('OpenLP.ProxyWidget', 'e.g. proxy_server_address:port_no')
self.layout.labelForField(self.http_edit).setText(translate('OpenLP.ProxyWidget', 'HTTP:'))
self.http_edit.setPlaceholderText(proxy_example)
self.layout.labelForField(self.https_edit).setText(translate('OpenLP.ProxyWidget', 'HTTPS:'))
self.https_edit.setPlaceholderText(proxy_example)
self.layout.labelForField(self.username_edit).setText(translate('OpenLP.ProxyWidget', 'Username:'))
self.layout.labelForField(self.password_edit).setText(translate('OpenLP.ProxyWidget', 'Password:'))
def load(self):
"""
Load the data from the settings to the widget.
"""
settings = Settings()
checked_radio = self.radio_group.button(settings.value('advanced/proxy mode'))
checked_radio.setChecked(True)
self.http_edit.setText(settings.value('advanced/proxy http'))
self.https_edit.setText(settings.value('advanced/proxy https'))
self.username_edit.setText(settings.value('advanced/proxy username'))
self.password_edit.setText(settings.value('advanced/proxy password'))
def save(self):
"""
Save the widget data to the settings
"""
settings = Settings() # TODO: Migrate from old system
settings.setValue('advanced/proxy mode', self.radio_group.checkedId())
settings.setValue('advanced/proxy http', self.http_edit.text())
settings.setValue('advanced/proxy https', self.https_edit.text())
settings.setValue('advanced/proxy username', self.username_edit.text())
settings.setValue('advanced/proxy password', self.password_edit.text())

View File

@ -28,6 +28,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import is_macosx
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
@ -105,8 +106,8 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
self.with_progress_page = add_progress_page
self.setFixedWidth(640)
self.setObjectName(name)
self.open_icon = build_icon(':/general/general_open.png')
self.delete_icon = build_icon(':/general/general_delete.png')
self.open_icon = UiIcons().open
self.delete_icon = UiIcons().delete
self.finish_button = self.button(QtWidgets.QWizard.FinishButton)
self.cancel_button = self.button(QtWidgets.QWizard.CancelButton)
self.setupUi(image)
@ -123,7 +124,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
Set up the wizard UI.
:param image: path to start up image
"""
self.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
self.setWindowIcon(UiIcons().main_icon)
self.setModal(True)
self.setOptions(QtWidgets.QWizard.IndependentPages |
QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage)
@ -192,12 +193,12 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
self.error_copy_to_button = QtWidgets.QPushButton(self.progress_page)
self.error_copy_to_button.setObjectName('error_copy_to_button')
self.error_copy_to_button.setHidden(True)
self.error_copy_to_button.setIcon(build_icon(':/system/system_edit_copy.png'))
self.error_copy_to_button.setIcon(UiIcons().copy)
self.error_button_layout.addWidget(self.error_copy_to_button)
self.error_save_to_button = QtWidgets.QPushButton(self.progress_page)
self.error_save_to_button.setObjectName('error_save_to_button')
self.error_save_to_button.setHidden(True)
self.error_save_to_button.setIcon(build_icon(':/general/general_save.png'))
self.error_save_to_button.setIcon(UiIcons().save)
self.error_button_layout.addWidget(self.error_save_to_button)
self.progress_layout.addLayout(self.error_button_layout)
self.addPage(self.progress_page)

View File

@ -28,11 +28,12 @@ from openlp.core.api.http import register_endpoint
from openlp.core.common.actions import ActionList
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.core.lib import Plugin, StringContent
from openlp.core.lib.db import Manager
from openlp.core.lib.theme import VerticalType
from openlp.core.lib.ui import create_action
from openlp.core.ui import AlertLocation
from openlp.core.ui.icons import UiIcons
from openlp.plugins.alerts.endpoint import api_alerts_endpoint, alerts_endpoint
from openlp.plugins.alerts.forms import AlertForm
from openlp.plugins.alerts.lib import AlertsManager, AlertsTab
@ -138,8 +139,8 @@ class AlertsPlugin(Plugin):
"""
super(AlertsPlugin, self).__init__('alerts', __default_settings__, settings_tab_class=AlertsTab)
self.weight = -3
self.icon_path = ':/plugins/plugin_alerts.png'
self.icon = build_icon(self.icon_path)
self.icon_path = UiIcons().alert
self.icon = self.icon_path
AlertsManager(self)
self.manager = Manager('alerts', init_schema)
self.alert_form = AlertForm(self)
@ -155,7 +156,7 @@ class AlertsPlugin(Plugin):
log.info('add tools menu')
self.tools_alert_item = create_action(tools_menu, 'toolsAlertItem',
text=translate('AlertsPlugin', '&Alert'),
icon=':/plugins/plugin_alerts.png',
icon=UiIcons().alert,
statustip=translate('AlertsPlugin', 'Show an alert message.'),
visible=False, can_shortcuts=True, triggers=self.on_alerts_trigger)
self.main_window.tools_menu.addAction(self.tools_alert_item)

View File

@ -23,7 +23,7 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
from openlp.core.lib.ui import create_button, create_button_box
@ -39,7 +39,7 @@ class Ui_AlertDialog(object):
"""
alert_dialog.setObjectName('alert_dialog')
alert_dialog.resize(400, 300)
alert_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
alert_dialog.setWindowIcon(UiIcons().main_icon)
self.alert_dialog_layout = QtWidgets.QGridLayout(alert_dialog)
self.alert_dialog_layout.setObjectName('alert_dialog_layout')
self.alert_text_layout = QtWidgets.QFormLayout()
@ -64,12 +64,12 @@ class Ui_AlertDialog(object):
self.manage_button_layout = QtWidgets.QVBoxLayout()
self.manage_button_layout.setObjectName('manage_button_layout')
self.new_button = QtWidgets.QPushButton(alert_dialog)
self.new_button.setIcon(build_icon(':/general/general_new.png'))
self.new_button.setIcon(UiIcons().new)
self.new_button.setObjectName('new_button')
self.manage_button_layout.addWidget(self.new_button)
self.save_button = QtWidgets.QPushButton(alert_dialog)
self.save_button.setEnabled(False)
self.save_button.setIcon(build_icon(':/general/general_save.png'))
self.save_button.setIcon(UiIcons().save)
self.save_button.setObjectName('save_button')
self.manage_button_layout.addWidget(self.save_button)
self.delete_button = create_button(alert_dialog, 'delete_button', role='delete', enabled=False,
@ -77,9 +77,8 @@ class Ui_AlertDialog(object):
self.manage_button_layout.addWidget(self.delete_button)
self.manage_button_layout.addStretch()
self.alert_dialog_layout.addLayout(self.manage_button_layout, 1, 1)
display_icon = build_icon(':/general/general_live.png')
self.display_button = create_button(alert_dialog, 'display_button', icon=display_icon, enabled=False)
self.display_close_button = create_button(alert_dialog, 'display_close_button', icon=display_icon,
self.display_button = create_button(alert_dialog, 'display_button', icon=UiIcons().live, enabled=False)
self.display_close_button = create_button(alert_dialog, 'display_close_button', icon=UiIcons().live,
enabled=False)
self.button_box = create_button_box(alert_dialog, 'button_box', ['close'],
[self.display_button, self.display_close_button])

View File

@ -25,6 +25,7 @@ import logging
from openlp.core.api.http import register_endpoint
from openlp.core.common.actions import ActionList
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.ui.icons import UiIcons
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.core.lib.ui import create_action
from openlp.plugins.bibles.endpoint import api_bibles_endpoint, bibles_endpoint
@ -74,8 +75,8 @@ class BiblePlugin(Plugin):
def __init__(self):
super(BiblePlugin, self).__init__('bibles', __default_settings__, BibleMediaItem, BiblesTab)
self.weight = -9
self.icon_path = ':/plugins/plugin_bibles.png'
self.icon = build_icon(self.icon_path)
self.icon_path = UiIcons().bible
self.icon = UiIcons().bible
self.manager = BibleManager(self)
register_endpoint(bibles_endpoint)
register_endpoint(api_bibles_endpoint)

View File

@ -23,14 +23,14 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_BookNameDialog(object):
def setupUi(self, book_name_dialog):
book_name_dialog.setObjectName('book_name_dialog')
book_name_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
book_name_dialog.setWindowIcon(UiIcons().main_icon)
book_name_dialog.resize(400, 271)
self.book_name_layout = QtWidgets.QVBoxLayout(book_name_dialog)
self.book_name_layout.setSpacing(8)

View File

@ -23,16 +23,16 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.plugins.bibles.lib import LanguageSelection, BibleStrings
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
from openlp.core.ui.icons import UiIcons
class Ui_EditBibleDialog(object):
def setupUi(self, edit_bible_dialog):
edit_bible_dialog.setObjectName('edit_bible_dialog')
edit_bible_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
edit_bible_dialog.setWindowIcon(UiIcons().main_icon)
edit_bible_dialog.resize(520, 400)
edit_bible_dialog.setModal(True)
self.dialog_layout = QtWidgets.QVBoxLayout(edit_bible_dialog)

View File

@ -183,7 +183,7 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties):
"""
Validate a book.
"""
book_regex = re.compile('[\d]*[^\d]+$')
book_regex = re.compile(r'[\d]*[^\d]+$')
if not new_book_name:
self.book_name_edit[abbreviation].setFocus()
critical_error_message_box(

View File

@ -23,14 +23,14 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_LanguageDialog(object):
def setupUi(self, language_dialog):
language_dialog.setObjectName('language_dialog')
language_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
language_dialog.setWindowIcon(UiIcons().main_icon)
language_dialog.resize(400, 165)
self.language_layout = QtWidgets.QVBoxLayout(language_dialog)
self.language_layout.setSpacing(8)

View File

@ -217,7 +217,7 @@ def update_reference_separators():
# add various Unicode alternatives
source_string = source_string.replace('-', '(?:[-\u00AD\u2010\u2011\u2012\u2014\u2014\u2212\uFE63\uFF0D])')
source_string = source_string.replace(',', '(?:[,\u201A])')
REFERENCE_SEPARATORS['sep_{role}'.format(role=role)] = '\s*(?:{source})\s*'.format(source=source_string)
REFERENCE_SEPARATORS['sep_{role}'.format(role=role)] = r'\s*(?:{source})\s*'.format(source=source_string)
REFERENCE_SEPARATORS['sep_{role}_default'.format(role=role)] = default_separators[index]
# verse range match: (<chapter>:)?<verse>(-((<chapter>:)?<verse>|end)?)?
range_regex = '(?:(?P<from_chapter>[0-9]+){sep_v})?' \
@ -255,7 +255,7 @@ def get_reference_match(match_type):
def parse_reference(reference, bible, language_selection, book_ref_id=False):
"""
r"""
This is the next generation über-awesome function that takes a person's typed in string and converts it to a list
of references to be queried from the Bible database files.

View File

@ -31,7 +31,8 @@ from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext
from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
critical_error_message_box, find_and_set_in_combo_box, build_icon
critical_error_message_box, find_and_set_in_combo_box
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.edits import SearchEdit
from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm
from openlp.plugins.bibles.forms.editbibleform import EditBibleForm
@ -41,7 +42,7 @@ from openlp.plugins.bibles.lib import DisplayStyle, LayoutStyle, VerseReferenceL
log = logging.getLogger(__name__)
VALID_TEXT_SEARCH = re.compile('\w\w\w')
VALID_TEXT_SEARCH = re.compile(r'\w\w\w')
def get_reference_separators():
@ -104,9 +105,9 @@ class BibleMediaItem(MediaManagerItem):
:param args: Positional arguments to pass to the super method. (tuple)
:param kwargs: Keyword arguments to pass to the super method. (dict)
"""
self.clear_icon = build_icon(':/bibles/bibles_search_clear.png')
self.save_results_icon = build_icon(':/bibles/bibles_save_results.png')
self.sort_icon = build_icon(':/bibles/bibles_book_sort.png')
self.clear_icon = UiIcons().square
self.save_results_icon = UiIcons.save
self.sort_icon = UiIcons().sort
self.bible = None
self.second_bible = None
self.saved_results = []
@ -314,13 +315,13 @@ class BibleMediaItem(MediaManagerItem):
self.plugin.manager.media = self
self.populate_bible_combo_boxes()
self.search_edit.set_search_types([
(BibleSearch.Combined, ':/bibles/bibles_search_combined.png',
(BibleSearch.Combined, UiIcons().search_comb,
translate('BiblesPlugin.MediaItem', 'Text or Reference'),
translate('BiblesPlugin.MediaItem', 'Text or Reference...')),
(BibleSearch.Reference, ':/bibles/bibles_search_reference.png',
(BibleSearch.Reference, UiIcons().search_ref,
translate('BiblesPlugin.MediaItem', 'Scripture Reference'),
translate('BiblesPlugin.MediaItem', 'Search Scripture Reference...')),
(BibleSearch.Text, ':/bibles/bibles_search_text.png',
(BibleSearch.Text, UiIcons().text,
translate('BiblesPlugin.MediaItem', 'Text Search'),
translate('BiblesPlugin.MediaItem', 'Search Text...'))
])

View File

@ -28,6 +28,7 @@ import logging
from openlp.core.api.http import register_endpoint
from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.core.lib.db import Manager
from openlp.plugins.custom.endpoint import api_custom_endpoint, custom_endpoint
@ -62,7 +63,7 @@ class CustomPlugin(Plugin):
super(CustomPlugin, self).__init__('custom', __default_settings__, CustomMediaItem, CustomTab)
self.weight = -5
self.db_manager = Manager('custom', init_schema)
self.icon_path = ':/plugins/plugin_custom.png'
self.icon_path = UiIcons().clone
self.icon = build_icon(self.icon_path)
register_endpoint(custom_endpoint)
register_endpoint(api_custom_endpoint)

View File

@ -22,8 +22,8 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box, create_button
from openlp.core.ui.icons import UiIcons
class Ui_CustomEditDialog(object):
@ -33,7 +33,7 @@ class Ui_CustomEditDialog(object):
:param custom_edit_dialog: The Dialog
"""
custom_edit_dialog.setObjectName('custom_edit_dialog')
custom_edit_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
custom_edit_dialog.setWindowIcon(UiIcons().main_icon)
custom_edit_dialog.resize(450, 350)
self.dialog_layout = QtWidgets.QVBoxLayout(custom_edit_dialog)
self.dialog_layout.setObjectName('dialog_layout')

View File

@ -23,23 +23,22 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.edits import SpellTextEdit
class Ui_CustomSlideEditDialog(object):
def setupUi(self, custom_slide_edit_dialog):
custom_slide_edit_dialog.setObjectName('custom_slide_edit_dialog')
custom_slide_edit_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
custom_slide_edit_dialog.setWindowIcon(UiIcons().main_icon)
custom_slide_edit_dialog.resize(350, 300)
self.dialog_layout = QtWidgets.QVBoxLayout(custom_slide_edit_dialog)
self.slide_text_edit = SpellTextEdit(self)
self.slide_text_edit.setObjectName('slide_text_edit')
self.dialog_layout.addWidget(self.slide_text_edit)
self.split_button = create_button(custom_slide_edit_dialog, 'splitButton', icon=':/general/general_add.png')
self.insert_button = create_button(custom_slide_edit_dialog, 'insertButton',
icon=':/general/general_add.png')
self.split_button = create_button(custom_slide_edit_dialog, 'splitButton', icon=UiIcons().add)
self.insert_button = create_button(custom_slide_edit_dialog, 'insertButton', icon=UiIcons().add)
self.button_box = create_button_box(custom_slide_edit_dialog, 'button_box', ['cancel', 'save'],
[self.split_button, self.insert_button])
self.dialog_layout.addWidget(self.button_box)

View File

@ -31,6 +31,7 @@ from openlp.core.common.settings import Settings
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext, PluginStatus, \
check_item_selected
from openlp.core.lib.ui import create_widget_action
from openlp.core.ui.icons import UiIcons
from openlp.plugins.custom.forms.editcustomform import EditCustomForm
from openlp.plugins.custom.lib import CustomXMLParser, CustomXMLBuilder
from openlp.plugins.custom.lib.db import CustomSlide
@ -88,7 +89,7 @@ class CustomMediaItem(MediaManagerItem):
def add_custom_context_actions(self):
create_widget_action(self.list_view, separator=True)
create_widget_action(
self.list_view, text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=':/general/general_clone.png',
self.list_view, text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=UiIcons().clone,
triggers=self.on_clone_click)
def config_update(self):
@ -111,9 +112,9 @@ class CustomMediaItem(MediaManagerItem):
Initialise the UI so it can provide Searches
"""
self.search_text_edit.set_search_types(
[(CustomSearch.Titles, ':/songs/song_search_title.png', translate('SongsPlugin.MediaItem', 'Titles'),
[(CustomSearch.Titles, UiIcons().search, translate('SongsPlugin.MediaItem', 'Titles'),
translate('SongsPlugin.MediaItem', 'Search Titles...')),
(CustomSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes)])
(CustomSearch.Themes, UiIcons().theme, UiStrings().Themes, UiStrings().SearchThemes)])
self.load_list(self.plugin.db_manager.get_all_objects(CustomSlide, order_by_ref=CustomSlide.title))
self.config_update()

View File

@ -26,6 +26,7 @@ from PyQt5 import QtGui
from openlp.core.api.http import register_endpoint
from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.settings import Settings
from openlp.core.lib import Plugin, StringContent, ImageSource, build_icon
from openlp.core.lib.db import Manager
@ -53,7 +54,7 @@ class ImagePlugin(Plugin):
super(ImagePlugin, self).__init__('images', __default_settings__, ImageMediaItem, ImageTab)
self.manager = Manager('images', init_schema, upgrade_mod=upgrade)
self.weight = -7
self.icon_path = ':/plugins/plugin_images.png'
self.icon_path = UiIcons().picture
self.icon = build_icon(self.icon_path)
register_endpoint(images_endpoint)
register_endpoint(api_images_endpoint)

View File

@ -33,6 +33,7 @@ from openlp.core.common.settings import Settings
from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, build_icon, \
check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.views import TreeWidgetWithDnD
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
@ -127,21 +128,21 @@ class ImageMediaItem(MediaManagerItem):
create_widget_action(
self.list_view,
text=self.plugin.get_string(StringContent.Edit)['title'],
icon=':/general/general_edit.png',
icon=UiIcons().edit,
triggers=self.on_edit_click)
create_widget_action(self.list_view, separator=True)
create_widget_action(
self.list_view,
'listView{name}{preview}Item'.format(name=self.plugin.name.title(), preview=StringContent.Preview.title()),
text=self.plugin.get_string(StringContent.Preview)['title'],
icon=':/general/general_preview.png',
icon=UiIcons().preview,
can_shortcuts=True,
triggers=self.on_preview_click)
create_widget_action(
self.list_view,
'listView{name}{live}Item'.format(name=self.plugin.name.title(), live=StringContent.Live.title()),
text=self.plugin.get_string(StringContent.Live)['title'],
icon=':/general/general_live.png',
icon=UiIcons().live,
can_shortcuts=True,
triggers=self.on_live_click)
create_widget_action(
@ -149,14 +150,14 @@ class ImageMediaItem(MediaManagerItem):
'listView{name}{service}Item'.format(name=self.plugin.name.title(), service=StringContent.Service.title()),
can_shortcuts=True,
text=self.plugin.get_string(StringContent.Service)['title'],
icon=':/general/general_add.png',
icon=UiIcons().add,
triggers=self.on_add_click)
if self.add_to_service_item:
create_widget_action(self.list_view, separator=True)
create_widget_action(
self.list_view,
text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'),
icon=':/general/general_add.png',
icon=UiIcons().add,
triggers=self.on_add_edit_click)
create_widget_action(self.list_view, separator=True)
if self.has_delete_icon:
@ -164,7 +165,7 @@ class ImageMediaItem(MediaManagerItem):
self.list_view,
'listView{name}{delete}Item'.format(name=self.plugin.name.title(), delete=StringContent.Delete.title()),
text=self.plugin.get_string(StringContent.Delete)['title'],
icon=':/general/general_delete.png',
icon=UiIcons().delete,
can_shortcuts=True, triggers=self.on_delete_click)
self.add_custom_context_actions()
# Create the context menu and add all actions from the list_view.
@ -182,17 +183,16 @@ class ImageMediaItem(MediaManagerItem):
create_widget_action(self.list_view, separator=True)
create_widget_action(
self.list_view,
text=UiStrings().AddGroup, icon=':/images/image_new_group.png', triggers=self.on_add_group_click)
text=UiStrings().AddGroup, icon=UiIcons().group, triggers=self.on_add_group_click)
create_widget_action(
self.list_view,
text=translate('ImagePlugin', 'Add new image(s)'),
icon=':/general/general_open.png', triggers=self.on_file_click)
icon=UiIcons().open, triggers=self.on_file_click)
create_widget_action(self.list_view, separator=True)
self.replace_action_context = create_widget_action(
self.list_view, text=UiStrings().ReplaceBG, icon=':/slides/slide_theme.png',
triggers=self.on_replace_click)
self.list_view, text=UiStrings().ReplaceBG, icon=UiIcons().theme, triggers=self.on_replace_click)
self.reset_action_context = create_widget_action(
self.list_view, text=UiStrings().ReplaceLiveBG, icon=':/system/system_close.png',
self.list_view, text=UiStrings().ReplaceLiveBG, icon=UiIcons().close,
visible=False, triggers=self.on_reset_click)
def add_start_header_bar(self):
@ -200,7 +200,7 @@ class ImageMediaItem(MediaManagerItem):
Add custom buttons to the start of the toolbar.
"""
self.add_group_action = self.toolbar.add_toolbar_action('add_group_action',
icon=':/images/image_new_group.png',
icon=UiIcons().group,
triggers=self.on_add_group_click)
def add_end_header_bar(self):
@ -208,10 +208,10 @@ class ImageMediaItem(MediaManagerItem):
Add custom buttons to the end of the toolbar
"""
self.replace_action = self.toolbar.add_toolbar_action('replace_action',
icon=':/slides/slide_theme.png',
icon=UiIcons().theme,
triggers=self.on_replace_click)
self.reset_action = self.toolbar.add_toolbar_action('reset_action',
icon=':/system/system_close.png',
icon=UiIcons().close,
visible=False, triggers=self.on_reset_click)
def recursively_delete_group(self, image_group):
@ -282,7 +282,7 @@ class ImageMediaItem(MediaManagerItem):
"""
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
image_groups.sort(key=lambda group_object: get_natural_key(group_object.group_name))
folder_icon = build_icon(':/images/image_group.png')
folder_icon = UiIcons().group
for image_group in image_groups:
group = QtWidgets.QTreeWidgetItem()
group.setText(0, image_group.group_name)
@ -371,7 +371,7 @@ class ImageMediaItem(MediaManagerItem):
file_name = image.file_path.name
thumbnail_path = self.generate_thumbnail_path(image)
if not image.file_path.exists():
icon = build_icon(':/general/general_delete.png')
icon = UiIcons().delete
else:
if validate_thumb(image.file_path, thumbnail_path):
icon = build_icon(thumbnail_path)

View File

@ -24,7 +24,7 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
class Ui_MediaClipSelector(object):
@ -106,7 +106,7 @@ class Ui_MediaClipSelector(object):
self.controls_layout = QtWidgets.QHBoxLayout()
self.controls_layout.setObjectName('controls_layout')
self.play_button = QtWidgets.QToolButton(media_clip_selector)
self.play_button.setIcon(build_icon(':/slides/media_playback_start.png'))
self.play_button.setIcon(UiIcons().play)
self.play_button.setObjectName('play_button')
self.controls_layout.addWidget(self.play_button)
self.position_slider = QtWidgets.QSlider(media_clip_selector)

View File

@ -25,13 +25,14 @@ import re
from datetime import datetime
from time import sleep
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import is_win, is_linux, is_macosx
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.path import Path
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media.vlcplayer import get_vlc
from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector
@ -66,12 +67,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
self.media_item = media_item
self.setupUi(self)
# setup play/pause icon
self.play_icon = QtGui.QIcon()
self.play_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal,
QtGui.QIcon.Off)
self.pause_icon = QtGui.QIcon()
self.pause_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_pause.png"), QtGui.QIcon.Normal,
QtGui.QIcon.Off)
self.play_icon = UiIcons().play
self.pause_icon = UiIcons().pause
def reject(self):
"""
@ -210,7 +207,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
# detect if we're dealing with a DVD or CD, so we use different loading approaches depending on the OS.
if is_win():
# If the given path is in the format "D:\" or "D:", prefix it with "/" to make VLC happy
pattern = re.compile('^\w:\\\\*$')
pattern = re.compile(r'^\w:\\\\*$')
if pattern.match(path):
path = '/' + path
self.vlc_media = self.vlc_instance.media_new_location('dvd://' + path)

View File

@ -32,9 +32,10 @@ from openlp.core.common.path import Path, path_to_str, create_paths
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, ServiceItem, ServiceItemContext, \
build_icon, check_item_selected
check_item_selected
from openlp.core.lib.ui import create_widget_action, critical_error_message_box, create_horizontal_adjusting_combo_box
from openlp.core.ui import DisplayControllerType
from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path, format_milliseconds
from openlp.core.ui.media.vlcplayer import get_vlc
@ -45,7 +46,7 @@ if get_vlc() is not None:
log = logging.getLogger(__name__)
CLAPPERBOARD = ':/media/slidecontroller_multimedia.png'
CLAPPERBOARD = UiIcons().clapperboard
class MediaMediaItem(MediaManagerItem, RegistryProperties):
@ -67,10 +68,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
self.icon_path = 'images/image'
self.background = False
self.automatic = ''
self.optical_icon = build_icon(':/media/media_optical.png')
self.video_icon = build_icon(':/media/media_video.png')
self.audio_icon = build_icon(':/media/media_audio.png')
self.error_icon = build_icon(':/general/general_delete.png')
self.error_icon = UiIcons().delete
def setup_item(self):
"""
@ -137,7 +135,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
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.')
self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=self.optical_icon,
self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=UiIcons().optical,
text=optical_button_text,
tooltip=optical_button_tooltip,
triggers=self.on_load_optical)
@ -149,13 +147,13 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
Adds buttons to the end of the header bar.
"""
# Replace backgrounds do not work at present so remove functionality.
self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_theme.png',
self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=UiIcons().theme,
triggers=self.on_replace_click)
if 'webkit' not in get_media_players()[0]:
self.replace_action.setDisabled(True)
if hasattr(self, 'replace_action_context'):
self.replace_action_context.setDisabled(True)
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png',
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=UiIcons().close,
visible=False, triggers=self.on_reset_click)
self.media_widget = QtWidgets.QWidget(self)
self.media_widget.setObjectName('media_widget')
@ -179,7 +177,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
self.list_view, text=UiStrings().ReplaceBG, icon=':/slides/slide_theme.png',
triggers=self.on_replace_click)
self.reset_action_context = create_widget_action(
self.list_view, text=UiStrings().ReplaceLiveBG, icon=':/system/system_close.png',
self.list_view, text=UiStrings().ReplaceLiveBG, icon=UiIcons().close,
visible=False, triggers=self.on_reset_click)
@staticmethod
@ -205,7 +203,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
def video_background_replaced(self):
"""
Triggered by main display on change of serviceitem.
Triggered by main display on change of service item.
"""
self.reset_action.setVisible(False)
self.reset_action_context.setVisible(False)
@ -369,7 +367,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
# Handle optical based item
(file_name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(track)
item_name = QtWidgets.QListWidgetItem(clip_name)
item_name.setIcon(self.optical_icon)
item_name.setIcon(UiIcons().optical)
item_name.setData(QtCore.Qt.UserRole, track)
item_name.setToolTip('{name}@{start}-{end}'.format(name=file_name,
start=format_milliseconds(start),
@ -378,7 +376,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
# File doesn't exist, mark as error.
file_name = os.path.split(str(track))[1]
item_name = QtWidgets.QListWidgetItem(file_name)
item_name.setIcon(self.error_icon)
item_name.setIcon(UiIcons().error)
item_name.setData(QtCore.Qt.UserRole, track)
item_name.setToolTip(track)
elif track_info.isFile():
@ -387,9 +385,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
item_name = QtWidgets.QListWidgetItem(file_name)
search = file_name.split('.')[-1].lower()
if '*.{text}'.format(text=search) in self.media_controller.audio_extensions_list:
item_name.setIcon(self.audio_icon)
item_name.setIcon(UiIcons().audio)
else:
item_name.setIcon(self.video_icon)
item_name.setIcon(UiIcons().video)
item_name.setData(QtCore.Qt.UserRole, track)
item_name.setToolTip(track)
if item_name:

View File

@ -31,6 +31,7 @@ from openlp.core.api.http import register_endpoint
from openlp.core.common import check_binary_exists
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.path import Path
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.plugins.media.endpoint import api_media_endpoint, media_endpoint
@ -56,7 +57,7 @@ class MediaPlugin(Plugin):
def __init__(self):
super(MediaPlugin, self).__init__('media', __default_settings__, MediaMediaItem)
self.weight = -6
self.icon_path = ':/plugins/plugin_media.png'
self.icon_path = UiIcons().video
self.icon = build_icon(self.icon_path)
# passed with drag and drop messages
self.dnd_id = 'Media'

View File

@ -30,15 +30,13 @@ from openlp.core.common.settings import Settings
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext, \
build_icon, check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
from openlp.core.ui.icons import UiIcons
from openlp.plugins.presentations.lib import MessageListener
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
log = logging.getLogger(__name__)
ERROR_IMAGE = QtGui.QImage(':/general/general_delete.png')
class PresentationMediaItem(MediaManagerItem):
"""
This is the Presentation media manager item for Presentation Items. It can present files using Openoffice and
@ -174,7 +172,7 @@ class PresentationMediaItem(MediaManagerItem):
file_name = file_path.name
if not file_path.exists():
item_name = QtWidgets.QListWidgetItem(file_name)
item_name.setIcon(build_icon(ERROR_IMAGE))
item_name.setIcon(UiIcons().delete)
item_name.setData(QtCore.Qt.UserRole, path_to_str(file_path))
item_name.setToolTip(str(file_path))
self.list_view.addItem(item_name)
@ -196,7 +194,7 @@ class PresentationMediaItem(MediaManagerItem):
preview_path = doc.get_thumbnail_path(1, True)
doc.close_presentation()
if not (preview_path and preview_path.exists()):
icon = build_icon(':/general/general_delete.png')
icon = UiIcons().delete
else:
if validate_thumb(preview_path, thumbnail_path):
icon = build_icon(thumbnail_path)
@ -204,7 +202,7 @@ class PresentationMediaItem(MediaManagerItem):
icon = create_thumb(preview_path, thumbnail_path)
else:
if initial_load:
icon = build_icon(':/general/general_delete.png')
icon = UiIcons().delete
else:
critical_error_message_box(UiStrings().UnsupportedFile,
translate('PresentationPlugin.MediaItem',

View File

@ -347,7 +347,7 @@ class MessageListener(object):
# Some of the original serviceitem attributes is needed in the new serviceitem
item.footer = item_cpy.footer
item.from_service = item_cpy.from_service
item.iconic_representation = item_cpy.iconic_representation
item.iconic_representation = item_cpy.icon
item.image_border = item_cpy.image_border
item.main = item_cpy.main
item.theme_data = item_cpy.theme_data

View File

@ -31,6 +31,7 @@ from PyQt5 import QtCore
from openlp.core.api.http import register_endpoint
from openlp.core.common import extension_loader
from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons
from openlp.core.common.settings import Settings
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.plugins.presentations.endpoint import api_presentations_endpoint, presentations_endpoint
@ -68,7 +69,7 @@ class PresentationPlugin(Plugin):
self.controllers = {}
Plugin.__init__(self, 'presentations', __default_settings__, __default_settings__)
self.weight = -8
self.icon_path = ':/plugins/plugin_presentations.png'
self.icon_path = UiIcons().presentation
self.icon = build_icon(self.icon_path)
register_endpoint(presentations_endpoint)
register_endpoint(api_presentations_endpoint)

View File

@ -23,8 +23,8 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_AuthorsDialog(object):
@ -37,7 +37,7 @@ class Ui_AuthorsDialog(object):
Set up the UI for the dialog.
"""
authors_dialog.setObjectName('authors_dialog')
authors_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
authors_dialog.setWindowIcon(UiIcons().main_icon)
authors_dialog.resize(300, 10)
authors_dialog.setModal(True)
self.dialog_layout = QtWidgets.QVBoxLayout(authors_dialog)

View File

@ -23,9 +23,9 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box, create_button
from openlp.core.ui import SingleColumnTableWidget
from openlp.core.ui.icons import UiIcons
from openlp.plugins.songs.lib.ui import SongStrings
@ -36,7 +36,7 @@ class Ui_EditSongDialog(object):
"""
def setupUi(self, edit_song_dialog):
edit_song_dialog.setObjectName('edit_song_dialog')
edit_song_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
edit_song_dialog.setWindowIcon(UiIcons().main_icon)
edit_song_dialog.resize(900, 600)
edit_song_dialog.setModal(True)
self.dialog_layout = QtWidgets.QVBoxLayout(edit_song_dialog)

View File

@ -105,7 +105,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.topics_list_view.setSortingEnabled(False)
self.topics_list_view.setAlternatingRowColors(True)
self.audio_list_widget.setAlternatingRowColors(True)
self.find_verse_split = re.compile('---\[\]---\n')
self.find_verse_split = re.compile(r'---\[\]---\n')
self.whitespace = re.compile(r'\W+')
self.find_tags = re.compile(r'\{/?\w+\}')
@ -316,7 +316,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
multiple.append(verse_tag)
self.song.lyrics = str(sxml.extract_xml(), 'utf-8')
for verse in multiple:
self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)',
self.song.verse_order = re.sub(r'([' + verse.upper() + verse.lower() + r'])(\W|$)',
r'\g<1>1\2', self.song.verse_order)
except:
log.exception('Problem processing song Lyrics \n{xml}'.format(xml=sxml.dump_xml()))

View File

@ -24,8 +24,8 @@ from PyQt5 import QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.edits import SpellTextEdit
from openlp.plugins.songs.lib import VerseType
@ -33,7 +33,7 @@ from openlp.plugins.songs.lib import VerseType
class Ui_EditVerseDialog(object):
def setupUi(self, edit_verse_dialog):
edit_verse_dialog.setObjectName('edit_verse_dialog')
edit_verse_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
edit_verse_dialog.setWindowIcon(UiIcons().main_icon)
edit_verse_dialog.resize(400, 400)
edit_verse_dialog.setModal(True)
self.dialog_layout = QtWidgets.QVBoxLayout(edit_verse_dialog)
@ -44,11 +44,11 @@ class Ui_EditVerseDialog(object):
self.verse_type_layout = QtWidgets.QHBoxLayout()
self.verse_type_layout.setObjectName('verse_type_layout')
self.forced_split_button = QtWidgets.QPushButton(edit_verse_dialog)
self.forced_split_button.setIcon(build_icon(':/general/general_add.png'))
self.forced_split_button.setIcon(UiIcons().add)
self.forced_split_button.setObjectName('forced_split_button')
self.verse_type_layout.addWidget(self.forced_split_button)
self.overflow_split_button = QtWidgets.QPushButton(edit_verse_dialog)
self.overflow_split_button.setIcon(build_icon(':/general/general_add.png'))
self.overflow_split_button.setIcon(UiIcons().add)
self.overflow_split_button.setObjectName('overflow_split_button')
self.verse_type_layout.addWidget(self.overflow_split_button)
self.verse_type_label = QtWidgets.QLabel(edit_verse_dialog)
@ -64,7 +64,7 @@ class Ui_EditVerseDialog(object):
self.verse_number_box.setObjectName('verse_number_box')
self.verse_type_layout.addWidget(self.verse_number_box)
self.insert_button = QtWidgets.QPushButton(edit_verse_dialog)
self.insert_button.setIcon(build_icon(':/general/general_add.png'))
self.insert_button.setIcon(UiIcons().add)
self.insert_button.setObjectName('insert_button')
self.verse_type_layout.addWidget(self.insert_button)
self.verse_type_layout.addStretch()
@ -76,11 +76,11 @@ class Ui_EditVerseDialog(object):
self.transpose_label.setObjectName('transpose_label')
self.transpose_layout.addWidget(self.transpose_label)
self.transpose_up_button = QtWidgets.QPushButton(edit_verse_dialog)
self.transpose_up_button.setIcon(build_icon(':/services/service_up.png'))
self.transpose_up_button.setIcon(UiIcons().arrow_up)
self.transpose_up_button.setObjectName('transpose_up')
self.transpose_layout.addWidget(self.transpose_up_button)
self.transpose_down_button = QtWidgets.QPushButton(edit_verse_dialog)
self.transpose_down_button.setIcon(build_icon(':/services/service_down.png'))
self.transpose_down_button.setIcon(UiIcons().arrow_down)
self.transpose_down_button.setObjectName('transpose_down')
self.transpose_layout.addWidget(self.transpose_down_button)
self.dialog_layout.addLayout(self.transpose_layout)

View File

@ -23,8 +23,8 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_MediaFilesDialog(object):
@ -36,7 +36,7 @@ class Ui_MediaFilesDialog(object):
Set up the user interface.
"""
media_files_dialog.setObjectName('media_files_dialog')
media_files_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
media_files_dialog.setWindowIcon(UiIcons().main_icon)
media_files_dialog.setWindowModality(QtCore.Qt.ApplicationModal)
media_files_dialog.resize(400, 300)
media_files_dialog.setModal(True)

View File

@ -23,8 +23,8 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_SongBookDialog(object):
@ -36,7 +36,7 @@ class Ui_SongBookDialog(object):
Set up the user interface.
"""
song_book_dialog.setObjectName('song_book_dialog')
song_book_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
song_book_dialog.setWindowIcon(UiIcons().main_icon)
song_book_dialog.resize(300, 10)
self.dialog_layout = QtWidgets.QVBoxLayout(song_book_dialog)
self.dialog_layout.setObjectName('dialog_layout')

View File

@ -23,8 +23,8 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
from openlp.plugins.songs.lib.ui import SongStrings
@ -37,7 +37,7 @@ class Ui_SongMaintenanceDialog(object):
Set up the user interface for the song maintenance dialog
"""
song_maintenance_dialog.setObjectName('song_maintenance_dialog')
song_maintenance_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
song_maintenance_dialog.setWindowIcon(UiIcons().main_icon)
song_maintenance_dialog.setWindowModality(QtCore.Qt.ApplicationModal)
song_maintenance_dialog.resize(600, 600)
self.dialog_layout = QtWidgets.QGridLayout(song_maintenance_dialog)
@ -47,11 +47,11 @@ class Ui_SongMaintenanceDialog(object):
self.type_list_widget.setUniformItemSizes(True)
self.type_list_widget.setObjectName('type_list_widget')
self.authors_list_item = QtWidgets.QListWidgetItem(self.type_list_widget)
self.authors_list_item.setIcon(build_icon(':/songs/author_maintenance.png'))
self.authors_list_item.setIcon(UiIcons().usermo)
self.topics_list_item = QtWidgets.QListWidgetItem(self.type_list_widget)
self.topics_list_item.setIcon(build_icon(':/songs/topic_maintenance.png'))
self.topics_list_item.setIcon(UiIcons().light_bulb)
self.books_list_item = QtWidgets.QListWidgetItem(self.type_list_widget)
self.books_list_item.setIcon(build_icon(':/songs/book_maintenance.png'))
self.books_list_item.setIcon(UiIcons().book)
self.dialog_layout.addWidget(self.type_list_widget, 0, 0)
self.stacked_layout = QtWidgets.QStackedLayout()
self.stacked_layout.setObjectName('stacked_layout')
@ -67,15 +67,15 @@ class Ui_SongMaintenanceDialog(object):
self.authors_buttons_layout.setObjectName('authors_buttons_layout')
self.authors_buttons_layout.addStretch()
self.add_author_button = QtWidgets.QPushButton(self.authors_page)
self.add_author_button.setIcon(build_icon(':/songs/author_add.png'))
self.add_author_button.setIcon(UiIcons().add)
self.add_author_button.setObjectName('add_author_button')
self.authors_buttons_layout.addWidget(self.add_author_button)
self.edit_author_button = QtWidgets.QPushButton(self.authors_page)
self.edit_author_button.setIcon(build_icon(':/songs/author_edit.png'))
self.edit_author_button.setIcon(UiIcons().edit)
self.edit_author_button.setObjectName('edit_author_button')
self.authors_buttons_layout.addWidget(self.edit_author_button)
self.delete_author_button = QtWidgets.QPushButton(self.authors_page)
self.delete_author_button.setIcon(build_icon(':/songs/author_delete.png'))
self.delete_author_button.setIcon(UiIcons().delete)
self.delete_author_button.setObjectName('delete_author_button')
self.authors_buttons_layout.addWidget(self.delete_author_button)
self.authors_layout.addLayout(self.authors_buttons_layout)
@ -92,15 +92,15 @@ class Ui_SongMaintenanceDialog(object):
self.topics_buttons_layout.setObjectName('topicsButtonLayout')
self.topics_buttons_layout.addStretch()
self.add_topic_button = QtWidgets.QPushButton(self.topics_page)
self.add_topic_button.setIcon(build_icon(':/songs/topic_add.png'))
self.add_topic_button.setIcon(UiIcons().add)
self.add_topic_button.setObjectName('add_topic_button')
self.topics_buttons_layout.addWidget(self.add_topic_button)
self.edit_topic_button = QtWidgets.QPushButton(self.topics_page)
self.edit_topic_button.setIcon(build_icon(':/songs/topic_edit.png'))
self.edit_topic_button.setIcon(UiIcons().edit)
self.edit_topic_button.setObjectName('edit_topic_button')
self.topics_buttons_layout.addWidget(self.edit_topic_button)
self.delete_topic_button = QtWidgets.QPushButton(self.topics_page)
self.delete_topic_button.setIcon(build_icon(':/songs/topic_delete.png'))
self.delete_topic_button.setIcon(UiIcons().delete)
self.delete_topic_button.setObjectName('delete_topic_button')
self.topics_buttons_layout.addWidget(self.delete_topic_button)
self.topics_layout.addLayout(self.topics_buttons_layout)
@ -117,15 +117,15 @@ class Ui_SongMaintenanceDialog(object):
self.books_buttons_layout.setObjectName('booksButtonLayout')
self.books_buttons_layout.addStretch()
self.add_book_button = QtWidgets.QPushButton(self.books_page)
self.add_book_button.setIcon(build_icon(':/songs/book_add.png'))
self.add_book_button.setIcon(UiIcons().add)
self.add_book_button.setObjectName('add_book_button')
self.books_buttons_layout.addWidget(self.add_book_button)
self.edit_book_button = QtWidgets.QPushButton(self.books_page)
self.edit_book_button.setIcon(build_icon(':/songs/book_edit.png'))
self.edit_book_button.setIcon(UiIcons().edit)
self.edit_book_button.setObjectName('edit_book_button')
self.books_buttons_layout.addWidget(self.edit_book_button)
self.delete_book_button = QtWidgets.QPushButton(self.books_page)
self.delete_book_button.setIcon(build_icon(':/songs/book_delete.png'))
self.delete_book_button.setIcon(UiIcons().delete)
self.delete_book_button.setObjectName('delete_book_button')
self.books_buttons_layout.addWidget(self.delete_book_button)
self.books_layout.addLayout(self.books_buttons_layout)

View File

@ -24,7 +24,7 @@ A widget representing a song in the duplicate song removal wizard review page.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.lib import build_icon
from openlp.core.ui.icons import UiIcons
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.openlyricsxml import SongXML
@ -182,7 +182,7 @@ class SongReviewWidget(QtWidgets.QWidget):
self.song_vertical_layout.addWidget(self.song_group_box)
self.song_remove_button = QtWidgets.QPushButton(self)
self.song_remove_button.setObjectName('song_remove_button')
self.song_remove_button.setIcon(build_icon(':/general/general_delete.png'))
self.song_remove_button.setIcon(UiIcons().delete)
self.song_remove_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self.song_vertical_layout.addWidget(self.song_remove_button, alignment=QtCore.Qt.AlignHCenter)

View File

@ -26,8 +26,8 @@ The :mod:`~openlp.plugins.songs.forms.songselectdialog` module contains the user
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.ui import SingleColumnTableWidget
from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.edits import HistoryComboBox
@ -90,7 +90,7 @@ class Ui_SongSelectDialog(object):
self.login_progress_bar.setVisible(False)
self.login_button_layout.addWidget(self.login_progress_bar)
self.login_button = QtWidgets.QPushButton(self.login_page)
self.login_button.setIcon(build_icon(':/songs/song_author_edit.png'))
self.login_button.setIcon(UiIcons().edit)
self.login_button.setObjectName('login_button')
self.login_button_layout.addWidget(self.login_button)
self.login_layout.setLayout(4, QtWidgets.QFormLayout.SpanningRole, self.login_button_layout)
@ -111,7 +111,7 @@ class Ui_SongSelectDialog(object):
self.search_combobox.setObjectName('search_combobox')
self.search_input_layout.addWidget(self.search_combobox)
self.search_button = QtWidgets.QPushButton(self.search_page)
self.search_button.setIcon(build_icon(':/general/general_find.png'))
self.search_button.setIcon(UiIcons().search)
self.search_button.setObjectName('search_button')
self.search_input_layout.addWidget(self.search_button)
self.search_layout.addLayout(self.search_input_layout)
@ -124,7 +124,7 @@ class Ui_SongSelectDialog(object):
self.search_progress_bar.setValue(0)
self.search_progress_layout.addWidget(self.search_progress_bar)
self.stop_button = QtWidgets.QPushButton(self.search_page)
self.stop_button.setIcon(build_icon(':/songs/song_search_stop.png'))
self.stop_button.setIcon(UiIcons().stop)
self.stop_button.setObjectName('stop_button')
self.search_progress_layout.addWidget(self.stop_button)
self.search_layout.addLayout(self.search_progress_layout)
@ -143,12 +143,12 @@ class Ui_SongSelectDialog(object):
self.view_layout.setSpacing(8)
self.view_layout.setObjectName('view_layout')
self.logout_button = QtWidgets.QPushButton(self.search_page)
self.logout_button.setIcon(build_icon(':/songs/song_author_edit.png'))
self.logout_button.setIcon(UiIcons().edit)
self.view_layout.addWidget(self.logout_button)
self.view_spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.view_layout.addItem(self.view_spacer)
self.view_button = QtWidgets.QPushButton(self.search_page)
self.view_button.setIcon(build_icon(':/songs/song_search_all.png'))
self.view_button.setIcon(UiIcons().search)
self.view_button.setObjectName('view_button')
self.view_layout.addWidget(self.view_button)
self.search_layout.addLayout(self.view_layout)
@ -203,14 +203,14 @@ class Ui_SongSelectDialog(object):
self.import_layout = QtWidgets.QHBoxLayout()
self.import_layout.setObjectName('import_layout')
self.back_button = QtWidgets.QPushButton(self.song_page)
self.back_button.setIcon(build_icon(':/general/general_back.png'))
self.back_button.setIcon(UiIcons().back)
self.back_button.setObjectName('back_button')
self.import_layout.addWidget(self.back_button)
self.import_spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Minimum)
self.import_layout.addItem(self.import_spacer)
self.import_button = QtWidgets.QPushButton(self.song_page)
self.import_button.setIcon(build_icon(':/general/general_import.png'))
self.import_button.setIcon(UiIcons().download)
self.import_button.setObjectName('import_button')
self.import_layout.addWidget(self.import_button)
self.song_layout.addLayout(self.import_layout, 5, 0, 1, 5)

View File

@ -23,8 +23,8 @@
from PyQt5 import QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.icons import UiIcons
class Ui_TopicsDialog(object):
@ -36,7 +36,7 @@ class Ui_TopicsDialog(object):
Set up the user interface for the topics dialog.
"""
topics_dialog.setObjectName('topics_dialog')
topics_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
topics_dialog.setWindowIcon(UiIcons().main_icon)
topics_dialog.resize(300, 10)
self.dialog_layout = QtWidgets.QVBoxLayout(topics_dialog)
self.dialog_layout.setObjectName('dialog_layout')

View File

@ -557,7 +557,7 @@ def transpose_lyrics(lyrics, transpose_value):
:return: The transposed lyrics
"""
# Split text by verse delimiter - both normal and optional
verse_list = re.split('(---\[.+?:.+?\]---|\[---\])', lyrics)
verse_list = re.split(r'(---\[.+?:.+?\]---|\[---\])', lyrics)
transposed_lyrics = ''
notation = Settings().value('songs/chord notation')
for verse in verse_list:
@ -580,7 +580,7 @@ def transpose_verse(verse_text, transpose_value, notation):
if '[' not in verse_text:
return verse_text
# Split the lyrics based on chord tags
lyric_list = re.split('(\[|\]|/)', verse_text)
lyric_list = re.split(r'(\[|\]|/)', verse_text)
transposed_lyrics = ''
in_tag = False
for word in lyric_list:

View File

@ -73,7 +73,7 @@ class DreamBeamImport(SongImport):
Valid extensions for a DreamBeam song file are:
* \*.xml
* .xml
"""
def do_import(self):

View File

@ -37,7 +37,7 @@ class EasySlidesImport(SongImport):
Import songs exported from EasySlides
The format example is here:
http://wiki.openlp.org/Development:EasySlides\_-_Song_Data_Format
http://wiki.openlp.org/Development:EasySlides_-_Song_Data_Format
"""
def __init__(self, manager, **kwargs):
"""
@ -210,7 +210,7 @@ class EasySlidesImport(SongImport):
vn = '1'
# have we got any digits?
# If so, versenumber is everything from the digits to the end
match = re.match('(.*)(\d+.*)', marker)
match = re.match(r'(.*)(\d+.*)', marker)
if match:
marker = match.group(1).strip()
vn = match.group(2)

View File

@ -273,15 +273,15 @@ class FoilPresenter(object):
elif copyright.find('C,)') != -1:
temp = copyright.partition('C,)')
copyright = temp[0]
copyright = re.compile('\\n').sub(' ', copyright)
copyright = re.compile('\(.*\)').sub('', copyright)
copyright = re.compile(r'\\n').sub(' ', copyright)
copyright = re.compile(r'\(.*\)').sub('', copyright)
if copyright.find('Rechte') != -1:
temp = copyright.partition('Rechte')
copyright = temp[0]
markers = ['Text +u\.?n?d? +Melodie[\w\,\. ]*:',
'Text +u\.?n?d? +Musik', 'T & M', 'Melodie und Satz',
'Text[\w\,\. ]*:', 'Melodie', 'Musik', 'Satz',
'Weise', '[dD]eutsch', '[dD]t[\.\:]', 'Englisch',
markers = [r'Text +u\.?n?d? +Melodie[\w\,\. ]*:',
r'Text +u\.?n?d? +Musik', 'T & M', 'Melodie und Satz',
r'Text[\w\,\. ]*:', 'Melodie', 'Musik', 'Satz',
'Weise', '[dD]eutsch', r'[dD]t[\.\:]', 'Englisch',
'[oO]riginal', 'Bearbeitung', '[R|r]efrain']
for marker in markers:
copyright = re.compile(marker).sub('<marker>', copyright, re.U)
@ -301,17 +301,17 @@ class FoilPresenter(object):
break
author_temp = []
for author in strings:
temp = re.split(',(?=\D{2})|(?<=\D),|\/(?=\D{3,})|(?<=\D);', author)
temp = re.split(r',(?=\D{2})|(?<=\D),|\/(?=\D{3,})|(?<=\D);', author)
for tempx in temp:
author_temp.append(tempx)
for author in author_temp:
regex = '^[\/,;\-\s\.]+|[\/,;\-\s\.]+$|\s*[0-9]{4}\s*[\-\/]?\s*([0-9]{4})?[\/,;\-\s\.]*$'
regex = r'^[\/,;\-\s\.]+|[\/,;\-\s\.]+$|\s*[0-9]{4}\s*[\-\/]?\s*([0-9]{4})?[\/,;\-\s\.]*$'
author = re.compile(regex).sub('', author)
author = re.compile('[0-9]{1,2}\.\s?J(ahr)?h\.|um\s*$|vor\s*$').sub('', author)
author = re.compile('[N|n]ach.*$').sub('', author)
author = re.compile(r'[0-9]{1,2}\.\s?J(ahr)?h\.|um\s*$|vor\s*$').sub('', author)
author = re.compile(r'[N|n]ach.*$').sub('', author)
author = author.strip()
if re.search('\w+\.?\s+\w{3,}\s+[a|u]nd\s|\w+\.?\s+\w{3,}\s+&\s', author, re.U):
temp = re.split('\s[a|u]nd\s|\s&\s', author)
if re.search(r'\w+\.?\s+\w{3,}\s+[a|u]nd\s|\w+\.?\s+\w{3,}\s+&\s', author, re.U):
temp = re.split(r'\s[a|u]nd\s|\s&\s', author)
for tempx in temp:
tempx = tempx.strip()
authors.append(tempx)

View File

@ -80,7 +80,7 @@ class LyrixImport(SongImport):
continue
# Detect and get CCLI number
if line.lower().startswith('ccli'):
ccli = re.findall('\d+', line)[0]
ccli = re.findall(r'\d+', line)[0]
try:
# If the CCLI was found, we are near the end
# Find author

View File

@ -156,7 +156,7 @@ class OpenSongImport(SongImport):
ustring = str(root.__getattr__(attr))
if isinstance(fn_or_string, str):
if attr in ['ccli']:
ustring = ''.join(re.findall('\d+', ustring))
ustring = ''.join(re.findall(r'\d+', ustring))
if ustring:
setattr(self, fn_or_string, int(ustring))
else:
@ -231,7 +231,7 @@ class OpenSongImport(SongImport):
content = this_line[1:right_bracket].lower()
# have we got any digits? If so, verse number is everything from the digits to the end (openlp does not
# have concept of part verses, so just ignore any non integers on the end (including floats))
match = re.match('(\D*)(\d+)', content)
match = re.match(r'(\D*)(\d+)', content)
if match is not None:
verse_tag = match.group(1)
verse_num = match.group(2)
@ -303,7 +303,7 @@ class OpenSongImport(SongImport):
# whitespace.
order = order.lower().split()
for verse_def in order:
match = re.match('(\D*)(\d+.*)', verse_def)
match = re.match(r'(\D*)(\d+.*)', verse_def)
if match is not None:
verse_tag = match.group(1)
verse_num = match.group(2)

View File

@ -122,7 +122,7 @@ class OPSProImport(SongImport):
# Try to split lyrics based on various rules
if lyrics:
lyrics_text = lyrics.Lyrics
verses = re.split('\r\n\s*?\r\n', lyrics_text)
verses = re.split(r'\r\n\s*?\r\n', lyrics_text)
verse_tag_defs = {}
verse_tag_texts = {}
for verse_text in verses:
@ -130,13 +130,13 @@ class OPSProImport(SongImport):
continue
verse_def = 'v'
# Detect verse number
verse_number = re.match('^(\d+)\r\n', verse_text)
verse_number = re.match(r'^(\d+)\r\n', verse_text)
if verse_number:
verse_text = re.sub('^\d+\r\n', '', verse_text)
verse_text = re.sub(r'^\d+\r\n', '', verse_text)
verse_def = 'v' + verse_number.group(1)
# Detect verse tags
elif re.match('^.+?\:\r\n', verse_text):
tag_match = re.match('^(.+?)\:\r\n(.*)', verse_text, flags=re.DOTALL)
elif re.match(r'^.+?\:\r\n', verse_text):
tag_match = re.match(r'^(.+?)\:\r\n(.*)', verse_text, flags=re.DOTALL)
tag = tag_match.group(1).lower()
tag = tag.split(' ')[0]
verse_text = tag_match.group(2)
@ -147,25 +147,25 @@ class OPSProImport(SongImport):
verse_tag_defs[tag] = verse_def
verse_tag_texts[tag] = verse_text
# Detect tag reference
elif re.match('^\(.*?\)$', verse_text):
tag_match = re.match('^\((.*?)\)$', verse_text)
elif re.match(r'^\(.*?\)$', verse_text):
tag_match = re.match(r'^\((.*?)\)$', verse_text)
tag = tag_match.group(1).lower()
if tag in verse_tag_defs:
verse_text = verse_tag_texts[tag]
verse_def = verse_tag_defs[tag]
# Detect end tag
elif re.match('^\[slot\]\r\n', verse_text, re.IGNORECASE):
elif re.match(r'^\[slot\]\r\n', verse_text, re.IGNORECASE):
verse_def = 'e'
verse_text = re.sub('^\[slot\]\r\n', '', verse_text, flags=re.IGNORECASE)
verse_text = re.sub(r'^\[slot\]\r\n', '', verse_text, flags=re.IGNORECASE)
# Replace the join tag with line breaks
verse_text = verse_text.replace('[join]', '')
# Replace the split tag with line breaks and an optional split
verse_text = re.sub('\[splits?\]', '\r\n[---]', verse_text)
verse_text = re.sub(r'\[splits?\]', '\r\n[---]', verse_text)
# Handle translations
if lyrics.IsDualLanguage:
verse_text = self.handle_translation(verse_text)
# Remove comments
verse_text = re.sub('\(.*?\)\r\n', '', verse_text, flags=re.IGNORECASE)
verse_text = re.sub(r'\(.*?\)\r\n', '', verse_text, flags=re.IGNORECASE)
self.add_verse(verse_text, verse_def)
self.finish()

View File

@ -70,7 +70,7 @@ class PowerSongImport(SongImport):
"""
Checks if source is a PowerSong 1.0 folder:
* is a directory
* contains at least one \*.song file
* contains at least one * .song file
:param openlp.core.common.path.Path import_source: Should be a Path object that fulfills the above criteria
:return: If the source is valid

View File

@ -51,7 +51,7 @@ class PresentationManagerImport(SongImport):
encoding = get_file_encoding(file_path)['encoding']
# Open file with detected encoding and remove encoding declaration
text = file_path.read_text(encoding=encoding)
text = re.sub('.+\?>\n', '', text)
text = re.sub(r'.+\?>\n', '', text)
try:
tree = etree.fromstring(text, parser=etree.XMLParser(recover=True))
except ValueError:

View File

@ -333,7 +333,7 @@ class SongsOfFellowshipImport(OpenOfficeImport):
There is a complicated word "One", which is sometimes lower and
sometimes upper depending on context. Never mind, keep it lower.
"""
text_arr = re.split('(\W+)', text)
text_arr = re.split(r'(\W+)', text)
text_arr[0] = text_arr[0].capitalize()
for i in range(1, len(text_arr)):
# Do not translate these. Fixed strings in SOF song file

View File

@ -142,7 +142,7 @@ class WorshipAssistantImport(SongImport):
# drop the square brackets
right_bracket = line.find(']')
content = line[1:right_bracket].lower()
match = re.match('(\D*)(\d+)', content)
match = re.match(r'(\D*)(\d+)', content)
if match is not None:
verse_tag = match.group(1)
verse_num = match.group(2)

Some files were not shown because too many files have changed in this diff Show More