forked from openlp/openlp
HEAD
This commit is contained in:
commit
a867c54b94
@ -290,7 +290,7 @@ def parse_options(args=None):
|
|||||||
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
|
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
|
||||||
"""
|
"""
|
||||||
# Set up command line options.
|
# Set up command line options.
|
||||||
parser = argparse.ArgumentParser(prog='openlp.py')
|
parser = argparse.ArgumentParser(prog='openlp')
|
||||||
parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
|
parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
|
||||||
help='Disable the error notification form.')
|
help='Disable the error notification form.')
|
||||||
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
|
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
|
||||||
|
@ -60,7 +60,6 @@ def get_local_ip4():
|
|||||||
|
|
||||||
:returns: Dict of interfaces
|
:returns: Dict of interfaces
|
||||||
"""
|
"""
|
||||||
# Get the local IPv4 active address(es) that are NOT localhost (lo or '127.0.0.1')
|
|
||||||
log.debug('Getting local IPv4 interface(es) information')
|
log.debug('Getting local IPv4 interface(es) information')
|
||||||
my_ip4 = {}
|
my_ip4 = {}
|
||||||
for iface in QNetworkInterface.allInterfaces():
|
for iface in QNetworkInterface.allInterfaces():
|
||||||
@ -70,8 +69,6 @@ def get_local_ip4():
|
|||||||
log.debug('Checking address(es) protocol')
|
log.debug('Checking address(es) protocol')
|
||||||
for address in iface.addressEntries():
|
for address in iface.addressEntries():
|
||||||
ip = address.ip()
|
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')
|
log.debug('Checking for protocol == IPv4Protocol')
|
||||||
if ip.protocol() == QAbstractSocket.IPv4Protocol:
|
if ip.protocol() == QAbstractSocket.IPv4Protocol:
|
||||||
log.debug('Getting interface information')
|
log.debug('Getting interface information')
|
||||||
@ -83,12 +80,13 @@ def get_local_ip4():
|
|||||||
ip.toIPv4Address()).toString()
|
ip.toIPv4Address()).toString()
|
||||||
}
|
}
|
||||||
log.debug('Adding {iface} to active list'.format(iface=iface.name()))
|
log.debug('Adding {iface} to active list'.format(iface=iface.name()))
|
||||||
|
if len(my_ip4) == 0:
|
||||||
|
log.warning('No active IPv4 network interfaces detected')
|
||||||
|
return my_ip4
|
||||||
if 'localhost' in my_ip4:
|
if 'localhost' in my_ip4:
|
||||||
log.debug('Renaming windows localhost to lo')
|
log.debug('Renaming windows localhost to lo')
|
||||||
my_ip4['lo'] = my_ip4['localhost']
|
my_ip4['lo'] = my_ip4['localhost']
|
||||||
my_ip4.pop('localhost')
|
my_ip4.pop('localhost')
|
||||||
if len(my_ip4) == 0:
|
|
||||||
log.warning('No active IPv4 network interfaces detected')
|
|
||||||
if len(my_ip4) == 1:
|
if len(my_ip4) == 1:
|
||||||
if 'lo' in my_ip4:
|
if 'lo' in my_ip4:
|
||||||
# No active interfaces - so leave localhost in there
|
# No active interfaces - so leave localhost in there
|
||||||
|
@ -26,19 +26,14 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import appdirs
|
||||||
|
|
||||||
import openlp
|
import openlp
|
||||||
from openlp.core.common import get_frozen_path, is_macosx, is_win
|
from openlp.core.common import get_frozen_path, is_macosx, is_win
|
||||||
from openlp.core.common.path import Path, create_paths
|
from openlp.core.common.path import Path, create_paths
|
||||||
from openlp.core.common.settings import Settings
|
from openlp.core.common.settings import Settings
|
||||||
|
|
||||||
|
|
||||||
if not is_win() and not is_macosx():
|
|
||||||
try:
|
|
||||||
from xdg import BaseDirectory
|
|
||||||
XDG_BASE_AVAILABLE = True
|
|
||||||
except ImportError:
|
|
||||||
XDG_BASE_AVAILABLE = False
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
FROZEN_APP_PATH = Path(sys.argv[0]).parent
|
FROZEN_APP_PATH = Path(sys.argv[0]).parent
|
||||||
@ -144,8 +139,10 @@ def _get_os_dir_path(dir_type):
|
|||||||
elif dir_type == AppLocation.LanguageDir:
|
elif dir_type == AppLocation.LanguageDir:
|
||||||
return Path(openlp.__file__).parent
|
return Path(openlp.__file__).parent
|
||||||
return openlp_folder_path
|
return openlp_folder_path
|
||||||
elif is_macosx():
|
|
||||||
openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp')
|
dirs = appdirs.AppDirs('openlp', multipath=True)
|
||||||
|
if is_macosx():
|
||||||
|
openlp_folder_path = Path(dirs.user_data_dir)
|
||||||
if dir_type == AppLocation.DataDir:
|
if dir_type == AppLocation.DataDir:
|
||||||
return openlp_folder_path / 'Data'
|
return openlp_folder_path / 'Data'
|
||||||
elif dir_type == AppLocation.LanguageDir:
|
elif dir_type == AppLocation.LanguageDir:
|
||||||
@ -153,15 +150,15 @@ def _get_os_dir_path(dir_type):
|
|||||||
return openlp_folder_path
|
return openlp_folder_path
|
||||||
else:
|
else:
|
||||||
if dir_type == AppLocation.LanguageDir:
|
if dir_type == AppLocation.LanguageDir:
|
||||||
directory = Path('/usr', 'local', 'share', 'openlp')
|
site_dirs = dirs.site_data_dir.split(os.pathsep)
|
||||||
|
directory = Path(site_dirs[0])
|
||||||
if directory.exists():
|
if directory.exists():
|
||||||
return directory
|
return directory
|
||||||
return Path('/usr', 'share', 'openlp')
|
return Path(site_dirs[1])
|
||||||
if XDG_BASE_AVAILABLE:
|
if dir_type == AppLocation.DataDir:
|
||||||
if dir_type == AppLocation.DataDir:
|
return Path(dirs.user_data_dir)
|
||||||
return Path(BaseDirectory.xdg_data_home, 'openlp')
|
elif dir_type == AppLocation.CacheDir:
|
||||||
elif dir_type == AppLocation.CacheDir:
|
return Path(dirs.user_cache_dir)
|
||||||
return Path(BaseDirectory.xdg_cache_home, 'openlp')
|
|
||||||
if dir_type == AppLocation.DataDir:
|
if dir_type == AppLocation.DataDir:
|
||||||
return Path(os.getenv('HOME'), '.openlp', 'data')
|
return Path(os.getenv('HOME'), '.openlp', 'data')
|
||||||
return Path(os.getenv('HOME'), '.openlp')
|
return Path(os.getenv('HOME'), '.openlp')
|
||||||
|
@ -58,8 +58,7 @@ class Registry(object):
|
|||||||
registry.functions_list = {}
|
registry.functions_list = {}
|
||||||
registry.working_flags = {}
|
registry.working_flags = {}
|
||||||
# Allow the tests to remove Registry entries but not the live system
|
# 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 = 'nose' in sys.argv[0] or 'pytest' in sys.argv[0]
|
||||||
registry.running_under_test = 'pytest' in sys.argv[0]
|
|
||||||
registry.initialising = True
|
registry.initialising = True
|
||||||
return registry
|
return registry
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@ -247,7 +247,8 @@ class Settings(QtCore.QSettings):
|
|||||||
'projector/last directory export': None,
|
'projector/last directory export': None,
|
||||||
'projector/poll time': 20, # PJLink timeout is 30 seconds
|
'projector/poll time': 20, # PJLink timeout is 30 seconds
|
||||||
'projector/socket timeout': 5, # 5 second socket timeout
|
'projector/socket timeout': 5, # 5 second socket timeout
|
||||||
'projector/source dialog type': 0 # Source select dialog box type
|
'projector/source dialog type': 0, # Source select dialog box type
|
||||||
|
'projector/udp broadcast listen': False # Enable/disable listening for PJLink 2 UDP broadcast packets
|
||||||
}
|
}
|
||||||
__file_path__ = ''
|
__file_path__ = ''
|
||||||
# Settings upgrades prior to 3.0
|
# Settings upgrades prior to 3.0
|
||||||
@ -306,7 +307,11 @@ class Settings(QtCore.QSettings):
|
|||||||
('songuasge/db database', 'songusage/db database', []),
|
('songuasge/db database', 'songusage/db database', []),
|
||||||
('presentations / Powerpoint Viewer', '', []),
|
('presentations / Powerpoint Viewer', '', []),
|
||||||
(['core/monitor', 'core/x position', 'core/y position', 'core/height', 'core/width', 'core/override',
|
(['core/monitor', 'core/x position', 'core/y position', 'core/height', 'core/width', 'core/override',
|
||||||
'core/display on monitor'], 'core/screens', [(upgrade_screens, [1, 0, 0, None, None, False, False])])
|
'core/display on monitor'], 'core/screens', [(upgrade_screens, [1, 0, 0, None, None, False, False])]),
|
||||||
|
('bibles/proxy name', '', []), # Just remove these bible proxy settings. They weren't used in 2.4!
|
||||||
|
('bibles/proxy address', '', []),
|
||||||
|
('bibles/proxy username', '', []),
|
||||||
|
('bibles/proxy password', '', [])
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -399,4 +399,4 @@ def create_separated_list(string_list):
|
|||||||
last=string_list[-1])
|
last=string_list[-1])
|
||||||
else:
|
else:
|
||||||
list_to_string = ''
|
list_to_string = ''
|
||||||
return list_to_string
|
return list_to_string
|
||||||
|
@ -180,6 +180,7 @@ class ProjectorEditForm(QtWidgets.QDialog, Ui_ProjectorEditForm):
|
|||||||
Validate input before accepting input.
|
Validate input before accepting input.
|
||||||
"""
|
"""
|
||||||
log.debug('accept_me() signal received')
|
log.debug('accept_me() signal received')
|
||||||
|
valid = True
|
||||||
if len(self.name_text.text().strip()) < 1:
|
if len(self.name_text.text().strip()) < 1:
|
||||||
QtWidgets.QMessageBox.warning(self,
|
QtWidgets.QMessageBox.warning(self,
|
||||||
translate('OpenLP.ProjectorEdit', 'Name Not Set'),
|
translate('OpenLP.ProjectorEdit', 'Name Not Set'),
|
||||||
|
@ -31,13 +31,14 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||||||
|
|
||||||
from openlp.core.common.i18n import translate
|
from openlp.core.common.i18n import translate
|
||||||
from openlp.core.common.mixins import LogMixin, RegistryProperties
|
from openlp.core.common.mixins import LogMixin, RegistryProperties
|
||||||
from openlp.core.common.registry import RegistryBase
|
from openlp.core.common.registry import Registry, RegistryBase
|
||||||
from openlp.core.common.settings import Settings
|
from openlp.core.common.settings import Settings
|
||||||
from openlp.core.lib.ui import create_widget_action
|
from openlp.core.lib.ui import create_widget_action
|
||||||
from openlp.core.projectors import DialogSourceStyle
|
from openlp.core.projectors import DialogSourceStyle
|
||||||
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT, \
|
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT,\
|
||||||
E_UNKNOWN_SOCKET_ERROR, PJLINK_PORT, QSOCKET_STATE, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, \
|
E_UNKNOWN_SOCKET_ERROR, QSOCKET_STATE, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, S_NOT_CONNECTED, S_OFF,\
|
||||||
S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG
|
S_ON, S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG
|
||||||
|
|
||||||
from openlp.core.projectors.db import ProjectorDB
|
from openlp.core.projectors.db import ProjectorDB
|
||||||
from openlp.core.projectors.editform import ProjectorEditForm
|
from openlp.core.projectors.editform import ProjectorEditForm
|
||||||
from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
|
from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
|
||||||
@ -297,7 +298,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
self.projector_list = []
|
self.projector_list = []
|
||||||
self.source_select_form = None
|
self.source_select_form = None
|
||||||
# Dictionary of PJLinkUDP objects to listen for UDP broadcasts from PJLink 2+ projectors.
|
# Dictionary of PJLinkUDP objects to listen for UDP broadcasts from PJLink 2+ projectors.
|
||||||
# Key is port number that projectors use
|
# Key is port number
|
||||||
self.pjlink_udp = {}
|
self.pjlink_udp = {}
|
||||||
# Dict for matching projector status to display icon
|
# Dict for matching projector status to display icon
|
||||||
self.status_icons = {
|
self.status_icons = {
|
||||||
@ -335,10 +336,6 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
"""
|
"""
|
||||||
Post-initialize setups.
|
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
|
# Set 1.5 second delay before loading all projectors
|
||||||
if self.autostart:
|
if self.autostart:
|
||||||
log.debug('Delaying 1.5 seconds before loading all projectors')
|
log.debug('Delaying 1.5 seconds before loading all projectors')
|
||||||
@ -351,6 +348,36 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
self.projector_form.editProjector.connect(self.edit_projector_from_wizard)
|
self.projector_form.editProjector.connect(self.edit_projector_from_wizard)
|
||||||
self.projector_list_widget.itemSelectionChanged.connect(self.update_icons)
|
self.projector_list_widget.itemSelectionChanged.connect(self.update_icons)
|
||||||
|
|
||||||
|
def udp_listen_add(self, port):
|
||||||
|
"""
|
||||||
|
Add UDP broadcast listener
|
||||||
|
"""
|
||||||
|
if port in self.pjlink_udp:
|
||||||
|
log.warning('UDP Listener for port {port} already added - skipping'.format(port=port))
|
||||||
|
else:
|
||||||
|
log.debug('Adding UDP listener on port {port}'.format(port=port))
|
||||||
|
self.pjlink_udp[port] = PJLinkUDP(port=port)
|
||||||
|
Registry().execute('udp_broadcast_add', port=port, callback=self.pjlink_udp[port].check_settings)
|
||||||
|
|
||||||
|
def udp_listen_delete(self, port):
|
||||||
|
"""
|
||||||
|
Remove a UDP broadcast listener
|
||||||
|
"""
|
||||||
|
log.debug('Checking for UDP port {port} listener deletion'.format(port=port))
|
||||||
|
if port not in self.pjlink_udp:
|
||||||
|
log.warn('UDP listener for port {port} not there - skipping delete'.format(port=port))
|
||||||
|
return
|
||||||
|
keep_port = False
|
||||||
|
for item in self.projector_list:
|
||||||
|
if port == item.link.port:
|
||||||
|
keep_port = True
|
||||||
|
if keep_port:
|
||||||
|
log.warn('UDP listener for port {port} needed for other projectors - skipping delete'.format(port=port))
|
||||||
|
return
|
||||||
|
Registry().execute('udp_broadcast_remove', port=port)
|
||||||
|
del self.pjlink_udp[port]
|
||||||
|
log.debug('UDP listener for port {port} deleted'.format(port=port))
|
||||||
|
|
||||||
def get_settings(self):
|
def get_settings(self):
|
||||||
"""
|
"""
|
||||||
Retrieve the saved settings
|
Retrieve the saved settings
|
||||||
@ -518,25 +545,22 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
except (AttributeError, TypeError):
|
except (AttributeError, TypeError):
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
projector.poll_timer.stop()
|
projector.link.poll_timer.stop()
|
||||||
projector.poll_timer.timeout.disconnect(projector.link.poll_loop)
|
projector.link.poll_timer.timeout.disconnect(projector.link.poll_loop)
|
||||||
except (AttributeError, TypeError):
|
except (AttributeError, TypeError):
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
projector.socket_timer.stop()
|
projector.link.socket_timer.stop()
|
||||||
projector.socket_timer.timeout.disconnect(projector.link.socket_abort)
|
projector.link.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):
|
except (AttributeError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
old_port = projector.link.port
|
||||||
# Rebuild projector list
|
# Rebuild projector list
|
||||||
new_list = []
|
new_list = []
|
||||||
for item in self.projector_list:
|
for item in self.projector_list:
|
||||||
if item.link.db_item.id == projector.link.db_item.id:
|
if item.link.db_item.id == projector.link.db_item.id:
|
||||||
|
log.debug('Removing projector "{item}"'.format(item=item.link.name))
|
||||||
continue
|
continue
|
||||||
new_list.append(item)
|
new_list.append(item)
|
||||||
self.projector_list = new_list
|
self.projector_list = new_list
|
||||||
@ -546,6 +570,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
log.warning('Delete projector {item} failed'.format(item=projector.db_item))
|
log.warning('Delete projector {item} failed'.format(item=projector.db_item))
|
||||||
for item in self.projector_list:
|
for item in self.projector_list:
|
||||||
log.debug('New projector list - item: {ip} {name}'.format(ip=item.link.ip, name=item.link.name))
|
log.debug('New projector list - item: {ip} {name}'.format(ip=item.link.ip, name=item.link.name))
|
||||||
|
self.udp_listen_delete(old_port)
|
||||||
|
|
||||||
def on_disconnect_projector(self, opt=None):
|
def on_disconnect_projector(self, opt=None):
|
||||||
"""
|
"""
|
||||||
@ -748,15 +773,8 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
item.link.projectorAuthentication.connect(self.authentication_error)
|
item.link.projectorAuthentication.connect(self.authentication_error)
|
||||||
item.link.projectorNoAuthentication.connect(self.no_authentication_error)
|
item.link.projectorNoAuthentication.connect(self.no_authentication_error)
|
||||||
item.link.projectorUpdateIcons.connect(self.update_icons)
|
item.link.projectorUpdateIcons.connect(self.update_icons)
|
||||||
# Connect UDP signal to projector instances with same port
|
# Add UDP listener for new projector port
|
||||||
if item.link.port not in self.pjlink_udp:
|
self.udp_listen_add(item.link.port)
|
||||||
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)
|
self.projector_list.append(item)
|
||||||
if start:
|
if start:
|
||||||
item.link.connect_to_host()
|
item.link.connect_to_host()
|
||||||
@ -783,13 +801,25 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
:param projector: Projector() instance of projector with updated information
|
:param projector: Projector() instance of projector with updated information
|
||||||
"""
|
"""
|
||||||
log.debug('edit_projector_from_wizard(ip={ip})'.format(ip=projector.ip))
|
log.debug('edit_projector_from_wizard(ip={ip})'.format(ip=projector.ip))
|
||||||
|
old_port = self.old_projector.link.port
|
||||||
|
old_ip = self.old_projector.link.ip
|
||||||
self.old_projector.link.name = projector.name
|
self.old_projector.link.name = projector.name
|
||||||
self.old_projector.link.ip = projector.ip
|
self.old_projector.link.ip = projector.ip
|
||||||
self.old_projector.link.pin = None if projector.pin == '' else projector.pin
|
self.old_projector.link.pin = None if projector.pin == '' else projector.pin
|
||||||
self.old_projector.link.port = projector.port
|
|
||||||
self.old_projector.link.location = projector.location
|
self.old_projector.link.location = projector.location
|
||||||
self.old_projector.link.notes = projector.notes
|
self.old_projector.link.notes = projector.notes
|
||||||
self.old_projector.widget.setText(projector.name)
|
self.old_projector.widget.setText(projector.name)
|
||||||
|
self.old_projector.link.port = int(projector.port)
|
||||||
|
# Update projector list items
|
||||||
|
for item in self.projector_list:
|
||||||
|
if item.link.ip == old_ip:
|
||||||
|
item.link.port = int(projector.port)
|
||||||
|
# NOTE: This assumes (!) we are using IP addresses as keys
|
||||||
|
break
|
||||||
|
# Update UDP listeners before setting old_projector.port
|
||||||
|
if old_port != projector.port:
|
||||||
|
self.udp_listen_delete(old_port)
|
||||||
|
self.udp_listen_add(int(projector.port))
|
||||||
|
|
||||||
def _load_projectors(self):
|
def _load_projectors(self):
|
||||||
"""'
|
"""'
|
||||||
|
@ -99,32 +99,51 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
|
|||||||
self.search_active = False
|
self.search_active = False
|
||||||
self.search_time = 30000 # 30 seconds for allowed time
|
self.search_time = 30000 # 30 seconds for allowed time
|
||||||
self.search_timer = QtCore.QTimer()
|
self.search_timer = QtCore.QTimer()
|
||||||
|
self.udp_broadcast_listen_setting = False
|
||||||
|
log.debug('(UDP:{port}) PJLinkUDP() Initialized'.format(port=self.port))
|
||||||
|
if Settings().value('projector/udp broadcast listen'):
|
||||||
|
self.udp_start()
|
||||||
|
|
||||||
|
def udp_start(self):
|
||||||
|
"""
|
||||||
|
Start listening on UDP port
|
||||||
|
"""
|
||||||
|
log.debug('(UDP:{port}) Start called'.format(port=self.port))
|
||||||
self.readyRead.connect(self.get_datagram)
|
self.readyRead.connect(self.get_datagram)
|
||||||
log.debug('(UDP) PJLinkUDP() Initialized for port {port}'.format(port=self.port))
|
self.check_settings(checked=Settings().value('projector/udp broadcast listen'))
|
||||||
|
|
||||||
|
def udp_stop(self):
|
||||||
|
"""
|
||||||
|
Stop listening on UDP port
|
||||||
|
"""
|
||||||
|
log.debug('(UDP:{port}) Stopping listener'.format(port=self.port))
|
||||||
|
self.close()
|
||||||
|
self.readyRead.disconnect(self.get_datagram)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def get_datagram(self):
|
def get_datagram(self):
|
||||||
"""
|
"""
|
||||||
Retrieve packet and basic checks
|
Retrieve packet and basic checks
|
||||||
"""
|
"""
|
||||||
log.debug('(UDP) get_datagram() - Receiving data')
|
log.debug('(UDP:{port}) get_datagram() - Receiving data'.format(port=self.port))
|
||||||
read_size = self.pendingDatagramSize()
|
read_size = self.pendingDatagramSize()
|
||||||
if -1 == read_size:
|
if -1 == read_size:
|
||||||
log.warning('(UDP) No data (-1)')
|
log.warning('(UDP:{port}) No data (-1)'.format(port=self.port))
|
||||||
return
|
return
|
||||||
elif 0 == read_size:
|
elif 0 == read_size:
|
||||||
log.warning('(UDP) get_datagram() called when pending data size is 0')
|
log.warning('(UDP:{port}) get_datagram() called when pending data size is 0'.format(port=self.port))
|
||||||
return
|
return
|
||||||
elif read_size > PJLINK_MAX_PACKET:
|
elif read_size > PJLINK_MAX_PACKET:
|
||||||
log.warning('(UDP) UDP Packet too large ({size} bytes)- ignoring'.format(size=read_size))
|
log.warning('(UDP:{port}) UDP Packet too large ({size} bytes)- ignoring'.format(size=read_size,
|
||||||
|
port=self.port))
|
||||||
return
|
return
|
||||||
data_in, peer_host, peer_port = self.readDatagram(read_size)
|
data_in, peer_host, peer_port = self.readDatagram(read_size)
|
||||||
data = data_in.decode('utf-8') if isinstance(data_in, bytes) else data_in
|
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),
|
log.debug('(UDP:{port}) {size} bytes received from {adx}'.format(size=len(data),
|
||||||
adx=peer_host.toString(),
|
adx=peer_host.toString(),
|
||||||
port=self.port))
|
port=self.port))
|
||||||
log.debug('(UDP) packet "{data}"'.format(data=data))
|
log.debug('(UDP:{port}) packet "{data}"'.format(data=data, port=self.port))
|
||||||
log.debug('(UDP) Sending data_received signal to projectors')
|
log.debug('(UDP:{port}) Sending data_received signal to projectors'.format(port=self.port))
|
||||||
self.data_received.emit(peer_host, self.localPort(), data)
|
self.data_received.emit(peer_host, self.localPort(), data)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -144,6 +163,25 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
|
|||||||
self.search_active = False
|
self.search_active = False
|
||||||
self.search_timer.stop()
|
self.search_timer.stop()
|
||||||
|
|
||||||
|
def check_settings(self, checked):
|
||||||
|
"""
|
||||||
|
Update UDP listening state based on settings change.
|
||||||
|
NOTE: This method is called by projector settings tab and setup/removed by ProjectorManager
|
||||||
|
"""
|
||||||
|
if self.udp_broadcast_listen_setting == checked:
|
||||||
|
log.debug('(UDP:{port}) No change to status - skipping'.format(port=self.port))
|
||||||
|
return
|
||||||
|
self.udp_broadcast_listen_setting = checked
|
||||||
|
if self.udp_broadcast_listen_setting:
|
||||||
|
if self.state() == self.ListeningState:
|
||||||
|
log.debug('(UDP:{port}) Already listening - skipping')
|
||||||
|
return
|
||||||
|
self.bind(self.port)
|
||||||
|
log.debug('(UDP:{port}) Listening'.format(port=self.port))
|
||||||
|
else:
|
||||||
|
# Close socket
|
||||||
|
self.udp_stop()
|
||||||
|
|
||||||
|
|
||||||
class PJLinkCommands(object):
|
class PJLinkCommands(object):
|
||||||
"""
|
"""
|
||||||
|
@ -27,6 +27,7 @@ import logging
|
|||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
from openlp.core.common.i18n import UiStrings, translate
|
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.common.settings import Settings
|
||||||
from openlp.core.lib.settingstab import SettingsTab
|
from openlp.core.lib.settingstab import SettingsTab
|
||||||
from openlp.core.projectors import DialogSourceStyle
|
from openlp.core.projectors import DialogSourceStyle
|
||||||
@ -48,8 +49,11 @@ class ProjectorTab(SettingsTab):
|
|||||||
:param parent: Parent widget
|
:param parent: Parent widget
|
||||||
"""
|
"""
|
||||||
self.icon_path = UiIcons().projector
|
self.icon_path = UiIcons().projector
|
||||||
|
self.udp_listeners = {} # Key on port number
|
||||||
projector_translated = translate('OpenLP.ProjectorTab', 'Projector')
|
projector_translated = translate('OpenLP.ProjectorTab', 'Projector')
|
||||||
super(ProjectorTab, self).__init__(parent, 'Projector', projector_translated)
|
super(ProjectorTab, self).__init__(parent, 'Projector', projector_translated)
|
||||||
|
Registry().register_function('udp_broadcast_add', self.add_udp_listener)
|
||||||
|
Registry().register_function('udp_broadcast_remove', self.remove_udp_listener)
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
"""
|
"""
|
||||||
@ -91,6 +95,10 @@ class ProjectorTab(SettingsTab):
|
|||||||
self.connect_box_layout.addRow(self.dialog_type_label, self.dialog_type_combo_box)
|
self.connect_box_layout.addRow(self.dialog_type_label, self.dialog_type_combo_box)
|
||||||
self.left_layout.addStretch()
|
self.left_layout.addStretch()
|
||||||
self.dialog_type_combo_box.activated.connect(self.on_dialog_type_combo_box_changed)
|
self.dialog_type_combo_box.activated.connect(self.on_dialog_type_combo_box_changed)
|
||||||
|
# Enable/disable listening on UDP ports for PJLink2 broadcasts
|
||||||
|
self.udp_broadcast_listen = QtWidgets.QCheckBox(self.connect_box)
|
||||||
|
self.udp_broadcast_listen.setObjectName('udp_broadcast_listen')
|
||||||
|
self.connect_box_layout.addRow(self.udp_broadcast_listen)
|
||||||
# Connect on LKUP packet received (PJLink v2+ only)
|
# Connect on LKUP packet received (PJLink v2+ only)
|
||||||
self.connect_on_linkup = QtWidgets.QCheckBox(self.connect_box)
|
self.connect_on_linkup = QtWidgets.QCheckBox(self.connect_box)
|
||||||
self.connect_on_linkup.setObjectName('connect_on_linkup')
|
self.connect_on_linkup.setObjectName('connect_on_linkup')
|
||||||
@ -117,6 +125,9 @@ class ProjectorTab(SettingsTab):
|
|||||||
translate('OpenLP.ProjectorTab', 'Single dialog box'))
|
translate('OpenLP.ProjectorTab', 'Single dialog box'))
|
||||||
self.connect_on_linkup.setText(
|
self.connect_on_linkup.setText(
|
||||||
translate('OpenLP.ProjectorTab', 'Connect to projector when LINKUP received (v2 only)'))
|
translate('OpenLP.ProjectorTab', 'Connect to projector when LINKUP received (v2 only)'))
|
||||||
|
self.udp_broadcast_listen.setText(
|
||||||
|
translate('OpenLP.ProjectorTab', 'Enable listening for PJLink2 broadcast messages'))
|
||||||
|
log.debug('PJLink settings tab initialized')
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
"""
|
"""
|
||||||
@ -126,6 +137,7 @@ class ProjectorTab(SettingsTab):
|
|||||||
self.socket_timeout_spin_box.setValue(Settings().value('projector/socket timeout'))
|
self.socket_timeout_spin_box.setValue(Settings().value('projector/socket timeout'))
|
||||||
self.socket_poll_spin_box.setValue(Settings().value('projector/poll time'))
|
self.socket_poll_spin_box.setValue(Settings().value('projector/poll time'))
|
||||||
self.dialog_type_combo_box.setCurrentIndex(Settings().value('projector/source dialog type'))
|
self.dialog_type_combo_box.setCurrentIndex(Settings().value('projector/source dialog type'))
|
||||||
|
self.udp_broadcast_listen.setChecked(Settings().value('projector/udp broadcast listen'))
|
||||||
self.connect_on_linkup.setChecked(Settings().value('projector/connect when LKUP received'))
|
self.connect_on_linkup.setChecked(Settings().value('projector/connect when LKUP received'))
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
@ -137,6 +149,41 @@ class ProjectorTab(SettingsTab):
|
|||||||
Settings().setValue('projector/poll time', self.socket_poll_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/source dialog type', self.dialog_type_combo_box.currentIndex())
|
||||||
Settings().setValue('projector/connect when LKUP received', self.connect_on_linkup.isChecked())
|
Settings().setValue('projector/connect when LKUP received', self.connect_on_linkup.isChecked())
|
||||||
|
Settings().setValue('projector/udp broadcast listen', self.udp_broadcast_listen.isChecked())
|
||||||
|
self.call_udp_listener()
|
||||||
|
|
||||||
def on_dialog_type_combo_box_changed(self):
|
def on_dialog_type_combo_box_changed(self):
|
||||||
self.dialog_type = self.dialog_type_combo_box.currentIndex()
|
self.dialog_type = self.dialog_type_combo_box.currentIndex()
|
||||||
|
|
||||||
|
def add_udp_listener(self, port, callback):
|
||||||
|
"""
|
||||||
|
Add new UDP listener to list
|
||||||
|
"""
|
||||||
|
if port in self.udp_listeners:
|
||||||
|
log.warning('Port {port} already in list - not adding'.format(port=port))
|
||||||
|
return
|
||||||
|
self.udp_listeners[port] = callback
|
||||||
|
log.debug('PJLinkSettings: new callback list: {port}'.format(port=self.udp_listeners.keys()))
|
||||||
|
|
||||||
|
def remove_udp_listener(self, port):
|
||||||
|
"""
|
||||||
|
Remove UDP listener from list
|
||||||
|
"""
|
||||||
|
if port not in self.udp_listeners:
|
||||||
|
log.warning('Port {port} not in list - ignoring'.format(port=port))
|
||||||
|
return
|
||||||
|
# Turn off listener before deleting
|
||||||
|
self.udp_listeners[port](checked=False)
|
||||||
|
del self.udp_listeners[port]
|
||||||
|
log.debug('PJLinkSettings: new callback list: {port}'.format(port=self.udp_listeners.keys()))
|
||||||
|
|
||||||
|
def call_udp_listener(self):
|
||||||
|
"""
|
||||||
|
Call listeners to update UDP listen setting
|
||||||
|
"""
|
||||||
|
if len(self.udp_listeners) < 1:
|
||||||
|
log.warning('PJLinkSettings: No callers - returning')
|
||||||
|
return
|
||||||
|
log.debug('PJLinkSettings: Calling UDP listeners')
|
||||||
|
for call in self.udp_listeners:
|
||||||
|
self.udp_listeners[call](checked=self.udp_broadcast_listen.isChecked())
|
||||||
|
@ -112,8 +112,8 @@ class UiAboutDialog(object):
|
|||||||
'Andreas "googol" Preikschat', 'Ken "alisonken1" Roberts', 'Raoul "superfly" Snyman',
|
'Andreas "googol" Preikschat', 'Ken "alisonken1" Roberts', 'Raoul "superfly" Snyman',
|
||||||
'Jonathan "springermac" Springer', 'Philip "Phill" Ridout']
|
'Jonathan "springermac" Springer', 'Philip "Phill" Ridout']
|
||||||
contributors = ['Stuart "sibecker" Becker', 'Gerald "jerryb" Britton', 'Jonathan "gushie" Corwin',
|
contributors = ['Stuart "sibecker" Becker', 'Gerald "jerryb" Britton', 'Jonathan "gushie" Corwin',
|
||||||
'Samuel "MrGamgee" Findlay', 'Michael "cocooncrash" Gorven', 'Scott "sguerrieri" Guerrieri',
|
'Samuel "MrGamgee" Findlay', 'Bastian Germann', 'Michael "cocooncrash" Gorven',
|
||||||
'Simon Hanna', 'Chris Hill',
|
'Scott "sguerrieri" Guerrieri', 'Simon Hanna', 'Chris Hill',
|
||||||
'Matthias "matthub" Hub', 'Meinert "m2j" Jordan', 'Ian Knightly'
|
'Matthias "matthub" Hub', 'Meinert "m2j" Jordan', 'Ian Knightly'
|
||||||
'Armin "orangeshirt" K\xf6hler',
|
'Armin "orangeshirt" K\xf6hler',
|
||||||
'Rafael "rafaellerm" Lerm', 'Gabriel loo', 'Erik "luen" Lundin', 'Edwin "edwinlunando" Lunando',
|
'Rafael "rafaellerm" Lerm', 'Gabriel loo', 'Erik "luen" Lundin', 'Edwin "edwinlunando" Lunando',
|
||||||
|
94
openlp/core/ui/fonts/LICENSE
Normal file
94
openlp/core/ui/fonts/LICENSE
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
Copyright Dave Gandy 2016. All rights reserved
|
||||||
|
with Reserved Font Name FontAwesome
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
@ -53,10 +53,6 @@ __default_settings__ = {
|
|||||||
'bibles/display new chapter': False,
|
'bibles/display new chapter': False,
|
||||||
'bibles/second bibles': True,
|
'bibles/second bibles': True,
|
||||||
'bibles/primary bible': '',
|
'bibles/primary bible': '',
|
||||||
'bibles/proxy name': '',
|
|
||||||
'bibles/proxy address': '',
|
|
||||||
'bibles/proxy username': '',
|
|
||||||
'bibles/proxy password': '',
|
|
||||||
'bibles/bible theme': '',
|
'bibles/bible theme': '',
|
||||||
'bibles/verse separator': '',
|
'bibles/verse separator': '',
|
||||||
'bibles/range separator': '',
|
'bibles/range separator': '',
|
||||||
|
@ -212,22 +212,22 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
self.open_song_layout.addRow(self.open_song_file_label, self.open_song_path_edit)
|
self.open_song_layout.addRow(self.open_song_file_label, self.open_song_path_edit)
|
||||||
self.open_song_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
|
self.open_song_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
|
||||||
self.select_stack.addWidget(self.open_song_widget)
|
self.select_stack.addWidget(self.open_song_widget)
|
||||||
self.web_tab_widget = QtWidgets.QTabWidget(self.select_page)
|
self.web_widget = QtWidgets.QWidget(self.select_page)
|
||||||
self.web_tab_widget.setObjectName('WebTabWidget')
|
self.web_widget.setObjectName('WebWidget')
|
||||||
self.web_bible_tab = QtWidgets.QWidget()
|
self.web_bible_tab = QtWidgets.QWidget()
|
||||||
self.web_bible_tab.setObjectName('WebBibleTab')
|
self.web_bible_tab.setObjectName('WebBibleTab')
|
||||||
self.web_bible_layout = QtWidgets.QFormLayout(self.web_bible_tab)
|
self.web_bible_layout = QtWidgets.QFormLayout(self.web_widget)
|
||||||
self.web_bible_layout.setObjectName('WebBibleLayout')
|
self.web_bible_layout.setObjectName('WebBibleLayout')
|
||||||
self.web_update_label = QtWidgets.QLabel(self.web_bible_tab)
|
self.web_update_label = QtWidgets.QLabel(self.web_widget)
|
||||||
self.web_update_label.setObjectName('WebUpdateLabel')
|
self.web_update_label.setObjectName('WebUpdateLabel')
|
||||||
self.web_bible_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.web_update_label)
|
self.web_bible_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.web_update_label)
|
||||||
self.web_update_button = QtWidgets.QPushButton(self.web_bible_tab)
|
self.web_update_button = QtWidgets.QPushButton(self.web_widget)
|
||||||
self.web_update_button.setObjectName('WebUpdateButton')
|
self.web_update_button.setObjectName('WebUpdateButton')
|
||||||
self.web_bible_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.web_update_button)
|
self.web_bible_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.web_update_button)
|
||||||
self.web_source_label = QtWidgets.QLabel(self.web_bible_tab)
|
self.web_source_label = QtWidgets.QLabel(self.web_widget)
|
||||||
self.web_source_label.setObjectName('WebSourceLabel')
|
self.web_source_label.setObjectName('WebSourceLabel')
|
||||||
self.web_bible_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.web_source_label)
|
self.web_bible_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.web_source_label)
|
||||||
self.web_source_combo_box = QtWidgets.QComboBox(self.web_bible_tab)
|
self.web_source_combo_box = QtWidgets.QComboBox(self.web_widget)
|
||||||
self.web_source_combo_box.setObjectName('WebSourceComboBox')
|
self.web_source_combo_box.setObjectName('WebSourceComboBox')
|
||||||
self.web_source_combo_box.addItems(['', '', ''])
|
self.web_source_combo_box.addItems(['', '', ''])
|
||||||
self.web_source_combo_box.setEnabled(False)
|
self.web_source_combo_box.setEnabled(False)
|
||||||
@ -245,31 +245,7 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
self.web_progress_bar.setObjectName('WebTranslationProgressBar')
|
self.web_progress_bar.setObjectName('WebTranslationProgressBar')
|
||||||
self.web_progress_bar.setVisible(False)
|
self.web_progress_bar.setVisible(False)
|
||||||
self.web_bible_layout.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.web_progress_bar)
|
self.web_bible_layout.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.web_progress_bar)
|
||||||
self.web_tab_widget.addTab(self.web_bible_tab, '')
|
self.select_stack.addWidget(self.web_widget)
|
||||||
self.web_proxy_tab = QtWidgets.QWidget()
|
|
||||||
self.web_proxy_tab.setObjectName('WebProxyTab')
|
|
||||||
self.web_proxy_layout = QtWidgets.QFormLayout(self.web_proxy_tab)
|
|
||||||
self.web_proxy_layout.setObjectName('WebProxyLayout')
|
|
||||||
self.web_server_label = QtWidgets.QLabel(self.web_proxy_tab)
|
|
||||||
self.web_server_label.setObjectName('WebServerLabel')
|
|
||||||
self.web_proxy_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.web_server_label)
|
|
||||||
self.web_server_edit = QtWidgets.QLineEdit(self.web_proxy_tab)
|
|
||||||
self.web_server_edit.setObjectName('WebServerEdit')
|
|
||||||
self.web_proxy_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.web_server_edit)
|
|
||||||
self.web_user_label = QtWidgets.QLabel(self.web_proxy_tab)
|
|
||||||
self.web_user_label.setObjectName('WebUserLabel')
|
|
||||||
self.web_proxy_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.web_user_label)
|
|
||||||
self.web_user_edit = QtWidgets.QLineEdit(self.web_proxy_tab)
|
|
||||||
self.web_user_edit.setObjectName('WebUserEdit')
|
|
||||||
self.web_proxy_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.web_user_edit)
|
|
||||||
self.web_password_label = QtWidgets.QLabel(self.web_proxy_tab)
|
|
||||||
self.web_password_label.setObjectName('WebPasswordLabel')
|
|
||||||
self.web_proxy_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.web_password_label)
|
|
||||||
self.web_password_edit = QtWidgets.QLineEdit(self.web_proxy_tab)
|
|
||||||
self.web_password_edit.setObjectName('WebPasswordEdit')
|
|
||||||
self.web_proxy_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.web_password_edit)
|
|
||||||
self.web_tab_widget.addTab(self.web_proxy_tab, '')
|
|
||||||
self.select_stack.addWidget(self.web_tab_widget)
|
|
||||||
self.zefania_widget = QtWidgets.QWidget(self.select_page)
|
self.zefania_widget = QtWidgets.QWidget(self.select_page)
|
||||||
self.zefania_widget.setObjectName('ZefaniaWidget')
|
self.zefania_widget.setObjectName('ZefaniaWidget')
|
||||||
self.zefania_layout = QtWidgets.QFormLayout(self.zefania_widget)
|
self.zefania_layout = QtWidgets.QFormLayout(self.zefania_widget)
|
||||||
@ -429,14 +405,6 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
self.web_source_combo_box.setItemText(WebDownload.Bibleserver, translate('BiblesPlugin.ImportWizardForm',
|
self.web_source_combo_box.setItemText(WebDownload.Bibleserver, translate('BiblesPlugin.ImportWizardForm',
|
||||||
'Bibleserver'))
|
'Bibleserver'))
|
||||||
self.web_translation_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible:'))
|
self.web_translation_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible:'))
|
||||||
self.web_tab_widget.setTabText(self.web_tab_widget.indexOf(self.web_bible_tab),
|
|
||||||
translate('BiblesPlugin.ImportWizardForm', 'Download Options'))
|
|
||||||
self.web_server_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Server:'))
|
|
||||||
self.web_user_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Username:'))
|
|
||||||
self.web_password_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Password:'))
|
|
||||||
self.web_tab_widget.setTabText(
|
|
||||||
self.web_tab_widget.indexOf(self.web_proxy_tab), translate('BiblesPlugin.ImportWizardForm',
|
|
||||||
'Proxy Server (Optional)'))
|
|
||||||
self.sword_bible_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bibles:'))
|
self.sword_bible_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bibles:'))
|
||||||
self.sword_folder_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD data folder:'))
|
self.sword_folder_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD data folder:'))
|
||||||
self.sword_zipfile_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD zip-file:'))
|
self.sword_zipfile_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD zip-file:'))
|
||||||
@ -611,11 +579,10 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
self.web_update_button.setEnabled(False)
|
self.web_update_button.setEnabled(False)
|
||||||
self.web_progress_bar.setVisible(True)
|
self.web_progress_bar.setVisible(True)
|
||||||
self.web_progress_bar.setValue(0)
|
self.web_progress_bar.setValue(0)
|
||||||
proxy_server = self.field('proxy_server')
|
|
||||||
# TODO: Where does critical_error_message_box get %s string from?
|
# TODO: Where does critical_error_message_box get %s string from?
|
||||||
for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract(proxy_server)),
|
for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract()),
|
||||||
(WebDownload.BibleGateway, BGExtract(proxy_server)),
|
(WebDownload.BibleGateway, BGExtract()),
|
||||||
(WebDownload.Bibleserver, BSExtract(proxy_server))):
|
(WebDownload.Bibleserver, BSExtract())):
|
||||||
try:
|
try:
|
||||||
bibles = extractor.get_bibles_from_http()
|
bibles = extractor.get_bibles_from_http()
|
||||||
except (urllib.error.URLError, ConnectionError) as err:
|
except (urllib.error.URLError, ConnectionError) as err:
|
||||||
@ -681,9 +648,6 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
self.select_page.registerField('web_biblename', self.web_translation_combo_box)
|
self.select_page.registerField('web_biblename', self.web_translation_combo_box)
|
||||||
self.select_page.registerField('sword_folder_path', self.sword_folder_path_edit, 'path', PathEdit.pathChanged)
|
self.select_page.registerField('sword_folder_path', self.sword_folder_path_edit, 'path', PathEdit.pathChanged)
|
||||||
self.select_page.registerField('sword_zip_path', self.sword_zipfile_path_edit, 'path', PathEdit.pathChanged)
|
self.select_page.registerField('sword_zip_path', self.sword_zipfile_path_edit, 'path', PathEdit.pathChanged)
|
||||||
self.select_page.registerField('proxy_server', self.web_server_edit)
|
|
||||||
self.select_page.registerField('proxy_username', self.web_user_edit)
|
|
||||||
self.select_page.registerField('proxy_password', self.web_password_edit)
|
|
||||||
self.license_details_page.registerField('license_version', self.version_name_edit)
|
self.license_details_page.registerField('license_version', self.version_name_edit)
|
||||||
self.license_details_page.registerField('license_copyright', self.copyright_edit)
|
self.license_details_page.registerField('license_copyright', self.copyright_edit)
|
||||||
self.license_details_page.registerField('license_permissions', self.permissions_edit)
|
self.license_details_page.registerField('license_permissions', self.permissions_edit)
|
||||||
@ -708,9 +672,6 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
self.setField('sword_zip_path', None)
|
self.setField('sword_zip_path', None)
|
||||||
self.setField('web_location', WebDownload.Crosswalk)
|
self.setField('web_location', WebDownload.Crosswalk)
|
||||||
self.setField('web_biblename', self.web_translation_combo_box.currentIndex())
|
self.setField('web_biblename', self.web_translation_combo_box.currentIndex())
|
||||||
self.setField('proxy_server', settings.value('proxy address'))
|
|
||||||
self.setField('proxy_username', settings.value('proxy username'))
|
|
||||||
self.setField('proxy_password', settings.value('proxy password'))
|
|
||||||
self.setField('license_version', self.version_name_edit.text())
|
self.setField('license_version', self.version_name_edit.text())
|
||||||
self.version_name_edit.setPlaceholderText(UiStrings().RequiredShowInFooter)
|
self.version_name_edit.setPlaceholderText(UiStrings().RequiredShowInFooter)
|
||||||
self.setField('license_copyright', self.copyright_edit.text())
|
self.setField('license_copyright', self.copyright_edit.text())
|
||||||
@ -767,9 +728,6 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
BibleFormat.WebDownload, name=license_version,
|
BibleFormat.WebDownload, name=license_version,
|
||||||
download_source=WebDownload.Names[download_location],
|
download_source=WebDownload.Names[download_location],
|
||||||
download_name=bible,
|
download_name=bible,
|
||||||
proxy_server=self.field('proxy_server'),
|
|
||||||
proxy_username=self.field('proxy_username'),
|
|
||||||
proxy_password=self.field('proxy_password'),
|
|
||||||
language_id=language_id
|
language_id=language_id
|
||||||
)
|
)
|
||||||
elif bible_type == BibleFormat.Zefania:
|
elif bible_type == BibleFormat.Zefania:
|
||||||
|
@ -83,20 +83,19 @@ def init_schema(url):
|
|||||||
|
|
||||||
meta_table = Table('metadata', metadata,
|
meta_table = Table('metadata', metadata,
|
||||||
Column('key', types.Unicode(255), primary_key=True, index=True),
|
Column('key', types.Unicode(255), primary_key=True, index=True),
|
||||||
Column('value', types.Unicode(255)),)
|
Column('value', types.Unicode(255)))
|
||||||
|
|
||||||
book_table = Table('book', metadata,
|
book_table = Table('book', metadata,
|
||||||
Column('id', types.Integer, primary_key=True),
|
Column('id', types.Integer, primary_key=True),
|
||||||
Column('book_reference_id', types.Integer, index=True),
|
Column('book_reference_id', types.Integer, index=True),
|
||||||
Column('testament_reference_id', types.Integer),
|
Column('testament_reference_id', types.Integer),
|
||||||
Column('name', types.Unicode(50), index=True),)
|
Column('name', types.Unicode(50), index=True))
|
||||||
verse_table = Table('verse', metadata,
|
verse_table = Table('verse', metadata,
|
||||||
Column('id', types.Integer, primary_key=True, index=True),
|
Column('id', types.Integer, primary_key=True, index=True),
|
||||||
Column('book_id', types.Integer, ForeignKey(
|
Column('book_id', types.Integer, ForeignKey('book.id'), index=True),
|
||||||
'book.id'), index=True),
|
|
||||||
Column('chapter', types.Integer, index=True),
|
Column('chapter', types.Integer, index=True),
|
||||||
Column('verse', types.Integer, index=True),
|
Column('verse', types.Integer, index=True),
|
||||||
Column('text', types.UnicodeText, index=True),)
|
Column('text', types.UnicodeText, index=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
class_mapper(BibleMeta)
|
class_mapper(BibleMeta)
|
||||||
|
@ -95,9 +95,8 @@ class BGExtract(RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
NAME = 'BibleGateway'
|
NAME = 'BibleGateway'
|
||||||
|
|
||||||
def __init__(self, proxy_url=None):
|
def __init__(self):
|
||||||
log.debug('BGExtract.init(proxy_url="{url}")'.format(url=proxy_url))
|
log.debug('BGExtract.__init__()')
|
||||||
self.proxy_url = proxy_url
|
|
||||||
socket.setdefaulttimeout(30)
|
socket.setdefaulttimeout(30)
|
||||||
|
|
||||||
def _remove_elements(self, parent, tag, class_=None):
|
def _remove_elements(self, parent, tag, class_=None):
|
||||||
@ -359,9 +358,8 @@ class BSExtract(RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
NAME = 'BibleServer'
|
NAME = 'BibleServer'
|
||||||
|
|
||||||
def __init__(self, proxy_url=None):
|
def __init__(self):
|
||||||
log.debug('BSExtract.init("{url}")'.format(url=proxy_url))
|
log.debug('BSExtract.__init__()')
|
||||||
self.proxy_url = proxy_url
|
|
||||||
socket.setdefaulttimeout(30)
|
socket.setdefaulttimeout(30)
|
||||||
|
|
||||||
def get_bible_chapter(self, version, book_name, chapter):
|
def get_bible_chapter(self, version, book_name, chapter):
|
||||||
@ -462,9 +460,8 @@ class CWExtract(RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
NAME = 'Crosswalk'
|
NAME = 'Crosswalk'
|
||||||
|
|
||||||
def __init__(self, proxy_url=None):
|
def __init__(self):
|
||||||
log.debug('CWExtract.init("{url}")'.format(url=proxy_url))
|
log.debug('CWExtract.__init__()')
|
||||||
self.proxy_url = proxy_url
|
|
||||||
socket.setdefaulttimeout(30)
|
socket.setdefaulttimeout(30)
|
||||||
|
|
||||||
def get_bible_chapter(self, version, book_name, chapter):
|
def get_bible_chapter(self, version, book_name, chapter):
|
||||||
@ -596,19 +593,9 @@ class HTTPBible(BibleImport, RegistryProperties):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.download_source = kwargs['download_source']
|
self.download_source = kwargs['download_source']
|
||||||
self.download_name = kwargs['download_name']
|
self.download_name = kwargs['download_name']
|
||||||
# TODO: Clean up proxy stuff. We probably want one global proxy per connection type (HTTP and HTTPS) at most.
|
|
||||||
self.proxy_server = None
|
|
||||||
self.proxy_username = None
|
|
||||||
self.proxy_password = None
|
|
||||||
self.language_id = None
|
self.language_id = None
|
||||||
if 'path' in kwargs:
|
if 'path' in kwargs:
|
||||||
self.path = kwargs['path']
|
self.path = kwargs['path']
|
||||||
if 'proxy_server' in kwargs:
|
|
||||||
self.proxy_server = kwargs['proxy_server']
|
|
||||||
if 'proxy_username' in kwargs:
|
|
||||||
self.proxy_username = kwargs['proxy_username']
|
|
||||||
if 'proxy_password' in kwargs:
|
|
||||||
self.proxy_password = kwargs['proxy_password']
|
|
||||||
if 'language_id' in kwargs:
|
if 'language_id' in kwargs:
|
||||||
self.language_id = kwargs['language_id']
|
self.language_id = kwargs['language_id']
|
||||||
|
|
||||||
@ -622,20 +609,12 @@ class HTTPBible(BibleImport, RegistryProperties):
|
|||||||
'Registering Bible and loading books...'))
|
'Registering Bible and loading books...'))
|
||||||
self.save_meta('download_source', self.download_source)
|
self.save_meta('download_source', self.download_source)
|
||||||
self.save_meta('download_name', self.download_name)
|
self.save_meta('download_name', self.download_name)
|
||||||
if self.proxy_server:
|
|
||||||
self.save_meta('proxy_server', self.proxy_server)
|
|
||||||
if self.proxy_username:
|
|
||||||
# Store the proxy userid.
|
|
||||||
self.save_meta('proxy_username', self.proxy_username)
|
|
||||||
if self.proxy_password:
|
|
||||||
# Store the proxy password.
|
|
||||||
self.save_meta('proxy_password', self.proxy_password)
|
|
||||||
if self.download_source.lower() == 'crosswalk':
|
if self.download_source.lower() == 'crosswalk':
|
||||||
handler = CWExtract(self.proxy_server)
|
handler = CWExtract()
|
||||||
elif self.download_source.lower() == 'biblegateway':
|
elif self.download_source.lower() == 'biblegateway':
|
||||||
handler = BGExtract(self.proxy_server)
|
handler = BGExtract()
|
||||||
elif self.download_source.lower() == 'bibleserver':
|
elif self.download_source.lower() == 'bibleserver':
|
||||||
handler = BSExtract(self.proxy_server)
|
handler = BSExtract()
|
||||||
books = handler.get_books_from_http(self.download_name)
|
books = handler.get_books_from_http(self.download_name)
|
||||||
if not books:
|
if not books:
|
||||||
log.error('Importing books from {source} - download name: "{name}" '
|
log.error('Importing books from {source} - download name: "{name}" '
|
||||||
@ -723,11 +702,11 @@ class HTTPBible(BibleImport, RegistryProperties):
|
|||||||
log.debug('HTTPBible.get_chapter("{book}", "{chapter}")'.format(book=book, chapter=chapter))
|
log.debug('HTTPBible.get_chapter("{book}", "{chapter}")'.format(book=book, chapter=chapter))
|
||||||
log.debug('source = {source}'.format(source=self.download_source))
|
log.debug('source = {source}'.format(source=self.download_source))
|
||||||
if self.download_source.lower() == 'crosswalk':
|
if self.download_source.lower() == 'crosswalk':
|
||||||
handler = CWExtract(self.proxy_server)
|
handler = CWExtract()
|
||||||
elif self.download_source.lower() == 'biblegateway':
|
elif self.download_source.lower() == 'biblegateway':
|
||||||
handler = BGExtract(self.proxy_server)
|
handler = BGExtract()
|
||||||
elif self.download_source.lower() == 'bibleserver':
|
elif self.download_source.lower() == 'bibleserver':
|
||||||
handler = BSExtract(self.proxy_server)
|
handler = BSExtract()
|
||||||
return handler.get_bible_chapter(self.download_name, book, chapter)
|
return handler.get_bible_chapter(self.download_name, book, chapter)
|
||||||
|
|
||||||
def get_books(self):
|
def get_books(self):
|
||||||
|
@ -118,7 +118,6 @@ class BibleManager(LogMixin, RegistryProperties):
|
|||||||
self.web = 'Web'
|
self.web = 'Web'
|
||||||
self.db_cache = None
|
self.db_cache = None
|
||||||
self.path = AppLocation.get_section_data_path(self.settings_section)
|
self.path = AppLocation.get_section_data_path(self.settings_section)
|
||||||
self.proxy_name = Settings().value(self.settings_section + '/proxy name')
|
|
||||||
self.suffix = '.sqlite'
|
self.suffix = '.sqlite'
|
||||||
self.import_wizard = None
|
self.import_wizard = None
|
||||||
self.reload_bibles()
|
self.reload_bibles()
|
||||||
@ -151,11 +150,8 @@ class BibleManager(LogMixin, RegistryProperties):
|
|||||||
if self.db_cache[name].is_web_bible:
|
if self.db_cache[name].is_web_bible:
|
||||||
source = self.db_cache[name].get_object(BibleMeta, 'download_source')
|
source = self.db_cache[name].get_object(BibleMeta, 'download_source')
|
||||||
download_name = self.db_cache[name].get_object(BibleMeta, 'download_name').value
|
download_name = self.db_cache[name].get_object(BibleMeta, 'download_name').value
|
||||||
meta_proxy = self.db_cache[name].get_object(BibleMeta, 'proxy_server')
|
|
||||||
web_bible = HTTPBible(self.parent, path=self.path, file=file_path, download_source=source.value,
|
web_bible = HTTPBible(self.parent, path=self.path, file=file_path, download_source=source.value,
|
||||||
download_name=download_name)
|
download_name=download_name)
|
||||||
if meta_proxy:
|
|
||||||
web_bible.proxy_server = meta_proxy.value
|
|
||||||
self.db_cache[name] = web_bible
|
self.db_cache[name] = web_bible
|
||||||
log.debug('Bibles reloaded')
|
log.debug('Bibles reloaded')
|
||||||
|
|
||||||
|
@ -24,9 +24,17 @@ The :mod:`upgrade` module provides a way for the database and schema that is the
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
from sqlalchemy import Table
|
||||||
|
from sqlalchemy.sql.expression import delete, select
|
||||||
|
|
||||||
|
from openlp.core.common.i18n import translate
|
||||||
|
from openlp.core.common.settings import ProxyMode, Settings
|
||||||
|
from openlp.core.lib.db import get_upgrade_op
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
__version__ = 1
|
__version__ = 2
|
||||||
|
|
||||||
|
|
||||||
# TODO: When removing an upgrade path the ftw-data needs updating to the minimum supported version
|
# TODO: When removing an upgrade path the ftw-data needs updating to the minimum supported version
|
||||||
@ -37,3 +45,48 @@ def upgrade_1(session, metadata):
|
|||||||
This upgrade renamed a number of keys to a single naming convention.
|
This upgrade renamed a number of keys to a single naming convention.
|
||||||
"""
|
"""
|
||||||
log.info('No upgrades to perform')
|
log.info('No upgrades to perform')
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade_2(session, metadata):
|
||||||
|
"""
|
||||||
|
Remove the individual proxy settings, after the implementation of central proxy settings.
|
||||||
|
Added in 2.5 (3.0 development)
|
||||||
|
"""
|
||||||
|
settings = Settings()
|
||||||
|
op = get_upgrade_op(session)
|
||||||
|
metadata_table = Table('metadata', metadata, autoload=True)
|
||||||
|
proxy, = session.execute(select([metadata_table.c.value], metadata_table.c.key == 'proxy_server')).first() or ('', )
|
||||||
|
if proxy and not \
|
||||||
|
(proxy == settings.value('advanced/proxy http') or proxy == settings.value('advanced/proxy https')):
|
||||||
|
http_proxy = ''
|
||||||
|
https_proxy = ''
|
||||||
|
name, = session.execute(select([metadata_table.c.value], metadata_table.c.key == 'name')).first()
|
||||||
|
msg_box = QtWidgets.QMessageBox()
|
||||||
|
msg_box.setText(translate('BiblesPlugin', f'The proxy server {proxy} was found in the bible {name}.<br>'
|
||||||
|
f'Would you like to set it as the proxy for OpenLP?'))
|
||||||
|
msg_box.setIcon(QtWidgets.QMessageBox.Question)
|
||||||
|
msg_box.addButton(QtWidgets.QMessageBox.No)
|
||||||
|
http_button = msg_box.addButton('http', QtWidgets.QMessageBox.ActionRole)
|
||||||
|
both_button = msg_box.addButton(translate('BiblesPlugin', 'both'), QtWidgets.QMessageBox.ActionRole)
|
||||||
|
https_button = msg_box.addButton('https', QtWidgets.QMessageBox.ActionRole)
|
||||||
|
msg_box.setDefaultButton(both_button)
|
||||||
|
msg_box.exec()
|
||||||
|
|
||||||
|
clicked_button = msg_box.clickedButton()
|
||||||
|
if clicked_button in [http_button, both_button]:
|
||||||
|
http_proxy = proxy
|
||||||
|
settings.setValue('advanced/proxy http', proxy)
|
||||||
|
if clicked_button in [https_button, both_button]:
|
||||||
|
https_proxy = proxy
|
||||||
|
settings.setValue('advanced/proxy https', proxy)
|
||||||
|
if http_proxy or https_proxy:
|
||||||
|
username, = session.execute(
|
||||||
|
select([metadata_table.c.value], metadata_table.c.key == 'proxy_username')).first()
|
||||||
|
proxy, = session.execute(select([metadata_table.c.value], metadata_table.c.key == 'proxy_password')).first()
|
||||||
|
settings.setValue('advanced/proxy username', username)
|
||||||
|
settings.setValue('advanced/proxy password', proxy)
|
||||||
|
settings.setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
|
||||||
|
op.execute(delete(metadata_table, metadata_table.c.key == 'proxy_server'))
|
||||||
|
op.execute(delete(metadata_table, metadata_table.c.key == 'proxy_username'))
|
||||||
|
op.execute(delete(metadata_table, metadata_table.c.key == 'proxy_password'))
|
||||||
|
@ -58,6 +58,7 @@ class Ui_ChooseGroupDialog(object):
|
|||||||
self.choose_group_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.existing_radio_button)
|
self.choose_group_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.existing_radio_button)
|
||||||
self.group_combobox = QtWidgets.QComboBox(choose_group_dialog)
|
self.group_combobox = QtWidgets.QComboBox(choose_group_dialog)
|
||||||
self.group_combobox.setObjectName('group_combobox')
|
self.group_combobox.setObjectName('group_combobox')
|
||||||
|
self.group_combobox.activated.connect(self.on_group_combobox_selected)
|
||||||
self.choose_group_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.group_combobox)
|
self.choose_group_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.group_combobox)
|
||||||
self.new_radio_button = QtWidgets.QRadioButton(choose_group_dialog)
|
self.new_radio_button = QtWidgets.QRadioButton(choose_group_dialog)
|
||||||
self.new_radio_button.setChecked(False)
|
self.new_radio_button.setChecked(False)
|
||||||
@ -65,6 +66,7 @@ class Ui_ChooseGroupDialog(object):
|
|||||||
self.choose_group_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.new_radio_button)
|
self.choose_group_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.new_radio_button)
|
||||||
self.new_group_edit = QtWidgets.QLineEdit(choose_group_dialog)
|
self.new_group_edit = QtWidgets.QLineEdit(choose_group_dialog)
|
||||||
self.new_group_edit.setObjectName('new_group_edit')
|
self.new_group_edit.setObjectName('new_group_edit')
|
||||||
|
self.new_group_edit.textEdited.connect(self.on_new_group_edit_changed)
|
||||||
self.choose_group_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.new_group_edit)
|
self.choose_group_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.new_group_edit)
|
||||||
self.group_button_box = create_button_box(choose_group_dialog, 'buttonBox', ['ok'])
|
self.group_button_box = create_button_box(choose_group_dialog, 'buttonBox', ['ok'])
|
||||||
self.choose_group_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.group_button_box)
|
self.choose_group_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.group_button_box)
|
||||||
@ -83,3 +85,22 @@ class Ui_ChooseGroupDialog(object):
|
|||||||
self.nogroup_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'No group'))
|
self.nogroup_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'No group'))
|
||||||
self.existing_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'Existing group'))
|
self.existing_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'Existing group'))
|
||||||
self.new_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'New group'))
|
self.new_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'New group'))
|
||||||
|
|
||||||
|
def on_group_combobox_selected(self, index):
|
||||||
|
"""
|
||||||
|
Handles the activated signal from the existing group combobox when the
|
||||||
|
user makes a selection
|
||||||
|
|
||||||
|
:param index: position of the selected item in the combobox
|
||||||
|
"""
|
||||||
|
self.existing_radio_button.setChecked(True)
|
||||||
|
self.group_combobox.setFocus()
|
||||||
|
|
||||||
|
def on_new_group_edit_changed(self, new_group):
|
||||||
|
"""
|
||||||
|
Handles the textEdited signal from the new group text input field
|
||||||
|
when the user enters a new group name
|
||||||
|
|
||||||
|
:param new_group: new text entered by the user
|
||||||
|
"""
|
||||||
|
self.new_radio_button.setChecked(True)
|
||||||
|
@ -48,4 +48,5 @@ class ChooseGroupForm(QtWidgets.QDialog, Ui_ChooseGroupDialog):
|
|||||||
for index in range(self.group_combobox.count()):
|
for index in range(self.group_combobox.count()):
|
||||||
if self.group_combobox.itemData(index) == selected_group:
|
if self.group_combobox.itemData(index) == selected_group:
|
||||||
self.group_combobox.setCurrentIndex(index)
|
self.group_combobox.setCurrentIndex(index)
|
||||||
|
self.existing_radio_button.setChecked(True)
|
||||||
return QtWidgets.QDialog.exec(self)
|
return QtWidgets.QDialog.exec(self)
|
||||||
|
@ -430,16 +430,6 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
|
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
|
||||||
preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
|
preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
|
||||||
# Enable and disable parts of the 'choose group' form
|
# Enable and disable parts of the 'choose group' form
|
||||||
if preselect_group is None:
|
|
||||||
self.choose_group_form.nogroup_radio_button.setChecked(True)
|
|
||||||
self.choose_group_form.nogroup_radio_button.setFocus()
|
|
||||||
self.choose_group_form.existing_radio_button.setChecked(False)
|
|
||||||
self.choose_group_form.new_radio_button.setChecked(False)
|
|
||||||
else:
|
|
||||||
self.choose_group_form.nogroup_radio_button.setChecked(False)
|
|
||||||
self.choose_group_form.existing_radio_button.setChecked(True)
|
|
||||||
self.choose_group_form.new_radio_button.setChecked(False)
|
|
||||||
self.choose_group_form.group_combobox.setFocus()
|
|
||||||
if self.manager.get_object_count(ImageGroups) == 0:
|
if self.manager.get_object_count(ImageGroups) == 0:
|
||||||
self.choose_group_form.existing_radio_button.setDisabled(True)
|
self.choose_group_form.existing_radio_button.setDisabled(True)
|
||||||
self.choose_group_form.group_combobox.setDisabled(True)
|
self.choose_group_form.group_combobox.setDisabled(True)
|
||||||
|
@ -44,7 +44,7 @@ def set_up_fault_handling():
|
|||||||
faulthandler.enable((AppLocation.get_directory(AppLocation.CacheDir) / 'error.log').open('wb'))
|
faulthandler.enable((AppLocation.get_directory(AppLocation.CacheDir) / 'error.log').open('wb'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def start():
|
||||||
"""
|
"""
|
||||||
Instantiate and run the application.
|
Instantiate and run the application.
|
||||||
"""
|
"""
|
||||||
@ -60,3 +60,7 @@ if __name__ == '__main__':
|
|||||||
if is_macosx():
|
if is_macosx():
|
||||||
sys.argv = [x for x in sys.argv if not x.startswith('-psn')]
|
sys.argv = [x for x in sys.argv if not x.startswith('-psn')]
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
start()
|
@ -11,11 +11,8 @@ environment:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
# Install dependencies from pypi
|
# Install dependencies from pypi
|
||||||
- "%PYTHON%\\python.exe -m pip install sqlalchemy alembic chardet beautifulsoup4 Mako nose mock pyodbc==4.0.8 psycopg2 pypiwin32==219 pyenchant websockets asyncio waitress six webob requests QtAwesome"
|
- "%PYTHON%\\python.exe -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python nose mock pyodbc==4.0.8 psycopg2 pypiwin32==219 pyenchant pymediainfo websockets asyncio waitress six webob requests QtAwesome"
|
||||||
# Install mysql dependency
|
# Download and install pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)
|
||||||
- "%PYTHON%\\python.exe -m pip install http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df"
|
|
||||||
# Download and install lxml and pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)
|
|
||||||
- "%PYTHON%\\python.exe -m pip install https://get.openlp.org/win-sdk/lxml-3.6.4-cp34-cp34m-win32.whl"
|
|
||||||
- "%PYTHON%\\python.exe -m pip install https://get.openlp.org/win-sdk/PyICU-1.9.5-cp34-cp34m-win32.whl"
|
- "%PYTHON%\\python.exe -m pip install https://get.openlp.org/win-sdk/PyICU-1.9.5-cp34-cp34m-win32.whl"
|
||||||
# Download and install PyQt5
|
# Download and install PyQt5
|
||||||
- appveyor DownloadFile http://downloads.sourceforge.net/project/pyqt/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32.exe
|
- appveyor DownloadFile http://downloads.sourceforge.net/project/pyqt/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32.exe
|
||||||
|
@ -33,25 +33,18 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
|
|
||||||
# If we try to import uno before nose this will create a warning. Just try to import nose first to suppress the warning.
|
|
||||||
try:
|
|
||||||
import nose
|
|
||||||
except ImportError:
|
|
||||||
nose = None
|
|
||||||
|
|
||||||
IS_WIN = sys.platform.startswith('win')
|
IS_WIN = sys.platform.startswith('win')
|
||||||
IS_LIN = sys.platform.startswith('lin')
|
IS_LIN = sys.platform.startswith('lin')
|
||||||
IS_MAC = sys.platform.startswith('dar')
|
IS_MAC = sys.platform.startswith('dar')
|
||||||
|
|
||||||
|
|
||||||
VERS = {
|
VERS = {
|
||||||
'Python': '3.4',
|
'Python': '3.6',
|
||||||
'PyQt5': '5.0',
|
'PyQt5': '5.0',
|
||||||
'Qt5': '5.0',
|
'Qt5': '5.0',
|
||||||
|
'pymediainfo': '2.2',
|
||||||
'sqlalchemy': '0.5',
|
'sqlalchemy': '0.5',
|
||||||
# pyenchant 1.6 required on Windows
|
'enchant': '1.6'
|
||||||
'enchant': '1.6' if IS_WIN else '1.3'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# pywin32
|
# pywin32
|
||||||
@ -59,7 +52,6 @@ WIN32_MODULES = [
|
|||||||
'win32com',
|
'win32com',
|
||||||
'win32ui',
|
'win32ui',
|
||||||
'pywintypes',
|
'pywintypes',
|
||||||
'pyodbc',
|
|
||||||
'icu',
|
'icu',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -85,19 +77,16 @@ MODULES = [
|
|||||||
'PyQt5.QtTest',
|
'PyQt5.QtTest',
|
||||||
'PyQt5.QtWebKit',
|
'PyQt5.QtWebKit',
|
||||||
'PyQt5.QtMultimedia',
|
'PyQt5.QtMultimedia',
|
||||||
|
'pymediainfo',
|
||||||
|
'appdirs',
|
||||||
'sqlalchemy',
|
'sqlalchemy',
|
||||||
'alembic',
|
'alembic',
|
||||||
'sqlite3',
|
|
||||||
'lxml',
|
'lxml',
|
||||||
'chardet',
|
'chardet',
|
||||||
'enchant',
|
|
||||||
'bs4',
|
'bs4',
|
||||||
'mako',
|
'mako',
|
||||||
'uno',
|
|
||||||
'websockets',
|
'websockets',
|
||||||
'asyncio',
|
|
||||||
'waitress',
|
'waitress',
|
||||||
'six',
|
|
||||||
'webob',
|
'webob',
|
||||||
'requests',
|
'requests',
|
||||||
'qtawesome'
|
'qtawesome'
|
||||||
@ -105,12 +94,17 @@ MODULES = [
|
|||||||
|
|
||||||
|
|
||||||
OPTIONAL_MODULES = [
|
OPTIONAL_MODULES = [
|
||||||
('mysql.connector', '(MySQL support)', True),
|
('mysql.connector', '(MySQL support)'),
|
||||||
('psycopg2', '(PostgreSQL support)', True),
|
('pyodbc', '(ODBC support)'),
|
||||||
('nose2', '(testing framework)', True),
|
('psycopg2', '(PostgreSQL support)'),
|
||||||
('mock', '(testing module)', sys.version_info[1] < 3),
|
('enchant', '(spell checker)'),
|
||||||
('jenkins', '(access jenkins api - package name: jenkins-webapi)', True),
|
('pysword', '(import SWORD bibles)'),
|
||||||
('pysword', '(import SWORD bibles)', True),
|
('uno', '(LibreOffice/OpenOffice support)'),
|
||||||
|
# development/testing modules
|
||||||
|
('jenkins', '(access jenkins api)'),
|
||||||
|
('launchpadlib', '(launchpad script support)'),
|
||||||
|
('nose2', '(testing framework)'),
|
||||||
|
('pylint', '(linter)')
|
||||||
]
|
]
|
||||||
|
|
||||||
w = sys.stdout.write
|
w = sys.stdout.write
|
||||||
@ -239,8 +233,7 @@ def main():
|
|||||||
check_module(m)
|
check_module(m)
|
||||||
print('Checking for optional modules...')
|
print('Checking for optional modules...')
|
||||||
for m in OPTIONAL_MODULES:
|
for m in OPTIONAL_MODULES:
|
||||||
if m[2]:
|
check_module(m[0], text=m[1])
|
||||||
check_module(m[0], text=m[1])
|
|
||||||
if IS_WIN:
|
if IS_WIN:
|
||||||
print('Checking for Windows specific modules...')
|
print('Checking for Windows specific modules...')
|
||||||
for m in WIN32_MODULES:
|
for m in WIN32_MODULES:
|
||||||
|
63
setup.py
63
setup.py
@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
@ -21,9 +22,10 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from subprocess import PIPE, Popen
|
import sys
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
from setuptools import find_packages, setup
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
|
||||||
VERSION_FILE = 'openlp/.version'
|
VERSION_FILE = 'openlp/.version'
|
||||||
@ -110,6 +112,34 @@ except Exception:
|
|||||||
finally:
|
finally:
|
||||||
ver_file.close()
|
ver_file.close()
|
||||||
|
|
||||||
|
requires = [
|
||||||
|
'alembic',
|
||||||
|
'appdirs',
|
||||||
|
'beautifulsoup4',
|
||||||
|
'chardet',
|
||||||
|
'lxml',
|
||||||
|
'Mako',
|
||||||
|
'pymediainfo >= 2.2',
|
||||||
|
'PyQt5',
|
||||||
|
'QtAwesome',
|
||||||
|
'requests',
|
||||||
|
'SQLAlchemy >= 0.5',
|
||||||
|
'waitress',
|
||||||
|
'WebOb',
|
||||||
|
'websockets'
|
||||||
|
]
|
||||||
|
if sys.platform.startswith('win'):
|
||||||
|
requires.extend([
|
||||||
|
'PyICU',
|
||||||
|
'pywin32'
|
||||||
|
])
|
||||||
|
elif sys.platform.startswith('darwin'):
|
||||||
|
requires.extend([
|
||||||
|
'pyobjc',
|
||||||
|
'pyobjc-framework-Cocoa'
|
||||||
|
])
|
||||||
|
elif sys.platform.startswith('linux'):
|
||||||
|
requires.append('dbus-python')
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='OpenLP',
|
name='OpenLP',
|
||||||
@ -157,18 +187,25 @@ using a computer and a data projector.""",
|
|||||||
keywords='open source church presentation lyrics projection song bible display project',
|
keywords='open source church presentation lyrics projection song bible display project',
|
||||||
author='Raoul Snyman',
|
author='Raoul Snyman',
|
||||||
author_email='raoulsnyman@openlp.org',
|
author_email='raoulsnyman@openlp.org',
|
||||||
url='http://openlp.org/',
|
url='https://openlp.org/',
|
||||||
license='GNU General Public License',
|
license='GNU General Public License',
|
||||||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
|
packages=find_packages(exclude=['ez_setup', 'tests']),
|
||||||
scripts=['openlp.py'],
|
py_modules=['run_openlp'],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
install_requires=[
|
python_requires='>=3.6',
|
||||||
# -*- Extra requirements: -*-
|
install_requires=requires,
|
||||||
'sqlalchemy',
|
extras_require={
|
||||||
'alembic'
|
'mysql': ['mysql-connector-python'],
|
||||||
],
|
'odbc': ['pyodbc'],
|
||||||
entry_points="""
|
'postgresql': ['psycopg2'],
|
||||||
# -*- Entry points: -*-
|
'spellcheck': ['pyenchant >= 1.6'],
|
||||||
"""
|
'sword-bibles': ['pysword'],
|
||||||
|
# Required for scripts/*.py:
|
||||||
|
'jenkins': ['python-jenkins'],
|
||||||
|
'launchpad': ['launchpadlib']
|
||||||
|
},
|
||||||
|
tests_require=['nose2', 'PyICU', 'pylint', 'pyodbc', 'pysword'],
|
||||||
|
test_suite='nose2.collector.collector',
|
||||||
|
entry_points={'gui_scripts': ['openlp = run_openlp:start']}
|
||||||
)
|
)
|
||||||
|
@ -8,10 +8,10 @@ Prerequisites
|
|||||||
|
|
||||||
In order to run the unit tests, you will need the following Python packages/libraries installed:
|
In order to run the unit tests, you will need the following Python packages/libraries installed:
|
||||||
|
|
||||||
- Mock
|
- pytest
|
||||||
- Nose
|
- pylint3
|
||||||
|
|
||||||
On Ubuntu you can simple install the python-mock and python-nose packages. Most other distributions will also have these
|
On Ubuntu you can simple install the python3-pytest and pylint3 packages. Most other distributions will also have these
|
||||||
packages. On Windows and Mac OS X you will need to use ``pip`` or ``easy_install`` to install these packages.
|
packages. On Windows and Mac OS X you will need to use ``pip`` or ``easy_install`` to install these packages.
|
||||||
|
|
||||||
Running the Tests
|
Running the Tests
|
||||||
@ -19,16 +19,12 @@ Running the Tests
|
|||||||
|
|
||||||
To run the tests, navigate to the root directory of the OpenLP project, and then run the following command::
|
To run the tests, navigate to the root directory of the OpenLP project, and then run the following command::
|
||||||
|
|
||||||
nosetests -v tests
|
pytest -v tests
|
||||||
|
|
||||||
Or, to run only the functional tests, run the following command::
|
Or, to run only the functional tests, run the following command::
|
||||||
|
|
||||||
nosetests -v tests/functional
|
pytest -v tests/functional
|
||||||
|
|
||||||
Or, to run only a particular test suite within a file, run the following command::
|
Or, to run only a particular test suite within a file, run the following command::
|
||||||
|
|
||||||
nosetests -v tests/functional/test_applocation.py
|
pytest -v tests/functional/openlp_core/test_app.py
|
||||||
|
|
||||||
Finally, to only run a particular test, run the following command::
|
|
||||||
|
|
||||||
nosetests -v tests/functional/test_applocation.py:TestAppLocation.get_frozen_path_test
|
|
||||||
|
@ -162,6 +162,7 @@ def test_check_same_instance():
|
|||||||
def test_get_language_from_settings():
|
def test_get_language_from_settings():
|
||||||
assert LanguageManager.get_language() == 'en'
|
assert LanguageManager.get_language() == 'en'
|
||||||
|
|
||||||
|
|
||||||
def test_get_language_from_settings_returns_unchanged_if_unknown_format():
|
def test_get_language_from_settings_returns_unchanged_if_unknown_format():
|
||||||
Settings().setValue('core/language', '(foobar)')
|
Settings().setValue('core/language', '(foobar)')
|
||||||
assert LanguageManager.get_language() == '(foobar)'
|
assert LanguageManager.get_language() == '(foobar)'
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2017 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 #
|
|
||||||
###############################################################################
|
|
||||||
"""
|
|
||||||
Functional tests to test calls for network interfaces.
|
|
||||||
"""
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, call, patch
|
|
||||||
|
|
||||||
import openlp.core.common
|
|
||||||
from openlp.core.common import get_local_ip4
|
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
lo_address_attrs = {'isValid.return_value': True,
|
|
||||||
'flags.return_value': True,
|
|
||||||
'InterfaceFlags.return_value': True,
|
|
||||||
'name.return_value': 'lo',
|
|
||||||
'broadcast.toString.return_value': '127.0.0.255',
|
|
||||||
'netmask.toString.return_value': '255.0.0.0',
|
|
||||||
'prefixLength.return_value': 8,
|
|
||||||
'ip.protocol.return_value': True}
|
|
||||||
|
|
||||||
|
|
||||||
class TestInterfaces(TestCase, TestMixin):
|
|
||||||
"""
|
|
||||||
A test suite to test out functions/methods that use network interface(s).
|
|
||||||
"""
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create an instance and a few example actions.
|
|
||||||
"""
|
|
||||||
self.build_settings()
|
|
||||||
|
|
||||||
self.ip4_lo_address = MagicMock()
|
|
||||||
self.ip4_lo_address.configure_mock(**lo_address_attrs)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
"""
|
|
||||||
Clean up
|
|
||||||
"""
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
@patch.object(openlp.core.common, 'log')
|
|
||||||
def test_ip4_no_interfaces(self, mock_log):
|
|
||||||
"""
|
|
||||||
Test no interfaces available
|
|
||||||
"""
|
|
||||||
# GIVEN: Test environment
|
|
||||||
call_warning = [call('No active IPv4 network interfaces detected')]
|
|
||||||
|
|
||||||
with patch('openlp.core.common.QNetworkInterface') as mock_newtork_interface:
|
|
||||||
mock_newtork_interface.allInterfaces.return_value = []
|
|
||||||
|
|
||||||
# WHEN: get_local_ip4 is called
|
|
||||||
ifaces = get_local_ip4()
|
|
||||||
|
|
||||||
# THEN: There should not be any interfaces detected
|
|
||||||
assert not ifaces, 'There should have been no active interfaces'
|
|
||||||
mock_log.warning.assert_has_calls(call_warning)
|
|
218
tests/functional/openlp_plugins/bibles/test_upgrade.py
Normal file
218
tests/functional/openlp_plugins/bibles/test_upgrade.py
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
# -*- 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
This module contains tests for the upgrade submodule of the Bibles plugin.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
from unittest import TestCase
|
||||||
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
|
from openlp.core.common.settings import ProxyMode
|
||||||
|
from openlp.core.lib.db import upgrade_db
|
||||||
|
from openlp.plugins.bibles.lib import upgrade
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
from tests.utils.constants import RESOURCE_PATH
|
||||||
|
|
||||||
|
|
||||||
|
class TestUpgrade(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
Test the `upgrade_2` function in the :mod:`upgrade` module when the db does not contains proxy metadata
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Setup for tests
|
||||||
|
"""
|
||||||
|
self.tmp_path = Path(mkdtemp())
|
||||||
|
db_path = RESOURCE_PATH / 'bibles' / 'web-bible-2.4.6-v1.sqlite'
|
||||||
|
db_tmp_path = self.tmp_path / 'web-bible-2.4.6-v1.sqlite'
|
||||||
|
shutil.copyfile(db_path, db_tmp_path)
|
||||||
|
self.db_url = 'sqlite:///' + str(db_tmp_path)
|
||||||
|
|
||||||
|
patched_settings = patch('openlp.plugins.bibles.lib.upgrade.Settings')
|
||||||
|
self.mocked_settings = patched_settings.start()
|
||||||
|
self.addCleanup(patched_settings.stop)
|
||||||
|
self.mocked_settings_instance = MagicMock()
|
||||||
|
self.mocked_settings.return_value = self.mocked_settings_instance
|
||||||
|
|
||||||
|
patched_message_box = patch('openlp.plugins.bibles.lib.upgrade.QtWidgets.QMessageBox')
|
||||||
|
self.mocked_message_box = patched_message_box.start()
|
||||||
|
self.addCleanup(patched_message_box.stop)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Clean up after tests
|
||||||
|
"""
|
||||||
|
# Ignore errors since windows can have problems with locked files
|
||||||
|
shutil.rmtree(self.tmp_path, ignore_errors=True)
|
||||||
|
|
||||||
|
def test_upgrade_2_none_selected(self):
|
||||||
|
"""
|
||||||
|
Test that upgrade 2 completes properly when the user chooses not to use a proxy ('No')
|
||||||
|
"""
|
||||||
|
# GIVEN: An version 1 web bible with proxy settings
|
||||||
|
|
||||||
|
# WHEN: Calling upgrade_db and the user has 'clicked' the 'No' button
|
||||||
|
upgrade_db(self.db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: The proxy meta data should have been removed, and the version should have been changed to version 2
|
||||||
|
self.mocked_message_box.assert_not_called()
|
||||||
|
engine = create_engine(self.db_url)
|
||||||
|
conn = engine.connect()
|
||||||
|
assert conn.execute('SELECT * FROM metadata WHERE key = "version"').first().value == '2'
|
||||||
|
|
||||||
|
|
||||||
|
class TestProxyMetaUpgrade(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
Test the `upgrade_2` function in the :mod:`upgrade` module when the db contains proxy metadata
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Setup for tests
|
||||||
|
"""
|
||||||
|
self.tmp_path = Path(mkdtemp())
|
||||||
|
db_path = RESOURCE_PATH / 'bibles' / 'web-bible-2.4.6-proxy-meta-v1.sqlite'
|
||||||
|
db_tmp_path = self.tmp_path / 'web-bible-2.4.6-proxy-meta-v1.sqlite'
|
||||||
|
shutil.copyfile(db_path, db_tmp_path)
|
||||||
|
self.db_url = 'sqlite:///' + str(db_tmp_path)
|
||||||
|
|
||||||
|
patched_settings = patch('openlp.plugins.bibles.lib.upgrade.Settings')
|
||||||
|
self.mocked_settings = patched_settings.start()
|
||||||
|
self.addCleanup(patched_settings.stop)
|
||||||
|
self.mocked_settings_instance = MagicMock()
|
||||||
|
self.mocked_settings.return_value = self.mocked_settings_instance
|
||||||
|
|
||||||
|
patched_message_box = patch('openlp.plugins.bibles.lib.upgrade.QtWidgets.QMessageBox')
|
||||||
|
mocked_message_box = patched_message_box.start()
|
||||||
|
self.addCleanup(patched_message_box.stop)
|
||||||
|
self.mocked_no_button = MagicMock()
|
||||||
|
self.mocked_http_button = MagicMock()
|
||||||
|
self.mocked_both_button = MagicMock()
|
||||||
|
self.mocked_https_button = MagicMock()
|
||||||
|
self.mocked_message_box_instance = MagicMock(
|
||||||
|
**{'addButton.side_effect': [self.mocked_no_button, self.mocked_http_button,
|
||||||
|
self.mocked_both_button, self.mocked_https_button]})
|
||||||
|
mocked_message_box.return_value = self.mocked_message_box_instance
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Clean up after tests
|
||||||
|
"""
|
||||||
|
# Ignore errors since windows can have problems with locked files
|
||||||
|
shutil.rmtree(self.tmp_path, ignore_errors=True)
|
||||||
|
|
||||||
|
def test_upgrade_2_none_selected(self):
|
||||||
|
"""
|
||||||
|
Test that upgrade 2 completes properly when the user chooses not to use a proxy ('No')
|
||||||
|
"""
|
||||||
|
# GIVEN: An version 1 web bible with proxy settings
|
||||||
|
|
||||||
|
# WHEN: Calling upgrade_db and the user has 'clicked' the 'No' button
|
||||||
|
self.mocked_message_box_instance.clickedButton.return_value = self.mocked_no_button
|
||||||
|
upgrade_db(self.db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: The proxy meta data should have been removed, and the version should have been changed to version 2
|
||||||
|
engine = create_engine(self.db_url)
|
||||||
|
conn = engine.connect()
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_server"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_username"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_password"').fetchall()) == 0
|
||||||
|
assert conn.execute('SELECT * FROM metadata WHERE key = "version"').first().value == '2'
|
||||||
|
self.mocked_settings_instance.setValue.assert_not_called()
|
||||||
|
|
||||||
|
def test_upgrade_2_http_selected(self):
|
||||||
|
"""
|
||||||
|
Test that upgrade 2 completes properly when the user chooses to use a HTTP proxy
|
||||||
|
"""
|
||||||
|
# GIVEN: An version 1 web bible with proxy settings
|
||||||
|
|
||||||
|
# WHEN: Calling upgrade_db and the user has 'clicked' the 'HTTP' button
|
||||||
|
self.mocked_message_box_instance.clickedButton.return_value = self.mocked_http_button
|
||||||
|
upgrade_db(self.db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: The proxy meta data should have been removed, the version should have been changed to version 2, and the
|
||||||
|
# proxy server saved to the settings
|
||||||
|
engine = create_engine(self.db_url)
|
||||||
|
conn = engine.connect()
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_server"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_username"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_password"').fetchall()) == 0
|
||||||
|
assert conn.execute('SELECT * FROM metadata WHERE key = "version"').first().value == '2'
|
||||||
|
|
||||||
|
assert self.mocked_settings_instance.setValue.call_args_list == [
|
||||||
|
call('advanced/proxy http', 'proxy_server'), call('advanced/proxy username', 'proxy_username'),
|
||||||
|
call('advanced/proxy password', 'proxy_password'), call('advanced/proxy mode', ProxyMode.MANUAL_PROXY)]
|
||||||
|
|
||||||
|
def test_upgrade_2_https_selected(self):
|
||||||
|
"""
|
||||||
|
Tcest that upgrade 2 completes properly when the user chooses to use a HTTPS proxy
|
||||||
|
"""
|
||||||
|
# GIVEN: An version 1 web bible with proxy settings
|
||||||
|
|
||||||
|
# WHEN: Calling upgrade_db and the user has 'clicked' the 'HTTPS' button
|
||||||
|
self.mocked_message_box_instance.clickedButton.return_value = self.mocked_https_button
|
||||||
|
upgrade_db(self.db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: The proxy settings should have been removed, the version should have been changed to version 2, and the
|
||||||
|
# proxy server saved to the settings
|
||||||
|
engine = create_engine(self.db_url)
|
||||||
|
conn = engine.connect()
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_server"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_username"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_password"').fetchall()) == 0
|
||||||
|
assert conn.execute('SELECT * FROM metadata WHERE key = "version"').first().value == '2'
|
||||||
|
|
||||||
|
assert self.mocked_settings_instance.setValue.call_args_list == [
|
||||||
|
call('advanced/proxy https', 'proxy_server'), call('advanced/proxy username', 'proxy_username'),
|
||||||
|
call('advanced/proxy password', 'proxy_password'), call('advanced/proxy mode', ProxyMode.MANUAL_PROXY)]
|
||||||
|
|
||||||
|
def test_upgrade_2_both_selected(self):
|
||||||
|
"""
|
||||||
|
Tcest that upgrade 2 completes properly when the user chooses to use a both HTTP and HTTPS proxies
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: An version 1 web bible with proxy settings
|
||||||
|
|
||||||
|
# WHEN: Calling upgrade_db
|
||||||
|
self.mocked_message_box_instance.clickedButton.return_value = self.mocked_both_button
|
||||||
|
upgrade_db(self.db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: The proxy settings should have been removed, the version should have been changed to version 2, and the
|
||||||
|
# proxy server saved to the settings
|
||||||
|
engine = create_engine(self.db_url)
|
||||||
|
conn = engine.connect()
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_server"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_username"').fetchall()) == 0
|
||||||
|
assert len(conn.execute('SELECT * FROM metadata WHERE key = "proxy_password"').fetchall()) == 0
|
||||||
|
assert conn.execute('SELECT * FROM metadata WHERE key = "version"').first().value == '2'
|
||||||
|
|
||||||
|
assert self.mocked_settings_instance.setValue.call_args_list == [
|
||||||
|
call('advanced/proxy http', 'proxy_server'), call('advanced/proxy https', 'proxy_server'),
|
||||||
|
call('advanced/proxy username', 'proxy_username'), call('advanced/proxy password', 'proxy_password'),
|
||||||
|
call('advanced/proxy mode', ProxyMode.MANUAL_PROXY)]
|
21
tests/interfaces/openlp_plugins/images/__init__.py
Normal file
21
tests/interfaces/openlp_plugins/images/__init__.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# -*- 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 #
|
||||||
|
###############################################################################
|
@ -0,0 +1,103 @@
|
|||||||
|
# -*- 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Tests for choosegroupform from the openlp.plugins.images.forms package.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from unittest import TestCase
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
|
from openlp.plugins.images.forms.choosegroupform import ChooseGroupForm
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class TestImageChooseGroupForm(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
Test the ChooseGroupForm class
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create the UI
|
||||||
|
"""
|
||||||
|
Registry.create()
|
||||||
|
self.setup_application()
|
||||||
|
self.main_window = QtWidgets.QMainWindow()
|
||||||
|
Registry().register('main_window', self.main_window)
|
||||||
|
self.form = ChooseGroupForm(self.main_window)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Cleanup
|
||||||
|
"""
|
||||||
|
del self.form
|
||||||
|
del self.main_window
|
||||||
|
|
||||||
|
def test_no_group_selected_by_default(self):
|
||||||
|
"""
|
||||||
|
Tests that the No Group option is the default selection
|
||||||
|
"""
|
||||||
|
assert self.form.nogroup_radio_button.isChecked()
|
||||||
|
|
||||||
|
def test_provided_group_is_selected(self):
|
||||||
|
"""
|
||||||
|
Tests preselected group initialization
|
||||||
|
"""
|
||||||
|
# GIVEN: There are some existing groups
|
||||||
|
QtWidgets.QDialog.exec = MagicMock(return_value=QtWidgets.QDialog.Accepted)
|
||||||
|
self.form.group_combobox.addItem('Group 1', 0)
|
||||||
|
self.form.group_combobox.addItem('Group 2', 1)
|
||||||
|
|
||||||
|
# WHEN: The form is displayed with preselected group index 1
|
||||||
|
self.form.exec(1)
|
||||||
|
|
||||||
|
# THEN: The Existing Group should be selected along with the radio button
|
||||||
|
assert self.form.group_combobox.currentIndex() == 1
|
||||||
|
assert self.form.existing_radio_button.isChecked()
|
||||||
|
|
||||||
|
def test_auto_select_existing_group_on_combo_selection(self):
|
||||||
|
"""
|
||||||
|
Tests that the Existing Group option becomes selected when changing the combobox
|
||||||
|
"""
|
||||||
|
# GIVEN: No preselected group was provided during initialization
|
||||||
|
assert not self.form.existing_radio_button.isChecked()
|
||||||
|
|
||||||
|
# WHEN: An existing group is selected from the combo box
|
||||||
|
self.form.on_group_combobox_selected(0)
|
||||||
|
|
||||||
|
# THEN: The Existing Group radio button should also be selected
|
||||||
|
assert self.form.existing_radio_button.isChecked()
|
||||||
|
|
||||||
|
def test_auto_select_new_group_on_edit(self):
|
||||||
|
"""
|
||||||
|
Tests that the New Group option becomes selected when changing the text field
|
||||||
|
"""
|
||||||
|
# GIVEN: The New Group option has not already been selected
|
||||||
|
assert not self.form.new_radio_button.isChecked()
|
||||||
|
|
||||||
|
# WHEN: The user enters text into the new group name text field
|
||||||
|
self.form.on_new_group_edit_changed('Test Group')
|
||||||
|
|
||||||
|
# THEN: The New Group radio button should also be selected
|
||||||
|
assert self.form.new_radio_button.isChecked()
|
223
tests/openlp_core/common/test_network_interfaces.py
Normal file
223
tests/openlp_core/common/test_network_interfaces.py
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2017 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Functional tests to test calls for network interfaces.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
from unittest.mock import call, patch
|
||||||
|
from PyQt5.QtCore import QObject
|
||||||
|
from PyQt5.QtNetwork import QHostAddress, QNetworkAddressEntry, QNetworkInterface
|
||||||
|
|
||||||
|
import openlp.core.common
|
||||||
|
from openlp.core.common import get_local_ip4
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class FakeIP4InterfaceEntry(QObject):
|
||||||
|
"""
|
||||||
|
Class to face an interface for testing purposes
|
||||||
|
"""
|
||||||
|
def __init__(self, name='lo'):
|
||||||
|
self.my_name = name
|
||||||
|
if name in ['localhost', 'lo']:
|
||||||
|
self.my_ip = QNetworkAddressEntry()
|
||||||
|
self.my_ip.setBroadcast(QHostAddress('255.0.0.0'))
|
||||||
|
self.my_ip.setIp(QHostAddress('127.0.0.2'))
|
||||||
|
self.my_ip.setPrefixLength(8)
|
||||||
|
self.fake_data = {'lo': {'ip': '127.0.0.2',
|
||||||
|
'broadcast': '255.0.0.0',
|
||||||
|
'netmask': '255.0.0.0',
|
||||||
|
'prefix': 8,
|
||||||
|
'localnet': '127.0.0.0'}}
|
||||||
|
else:
|
||||||
|
# Define a fake real address
|
||||||
|
self.my_ip = QNetworkAddressEntry()
|
||||||
|
self.my_ip.setBroadcast(QHostAddress('255.255.255.0'))
|
||||||
|
self.my_ip.setIp(QHostAddress('127.254.0.2'))
|
||||||
|
self.my_ip.setPrefixLength(24)
|
||||||
|
self.fake_data = {self.my_name: {'ip': '127.254.0.2',
|
||||||
|
'broadcast': '255.255.255.0',
|
||||||
|
'netmask': '255.255.255.0',
|
||||||
|
'prefix': 24,
|
||||||
|
'localnet': '127.254.0.0'}}
|
||||||
|
|
||||||
|
def addressEntries(self):
|
||||||
|
"""
|
||||||
|
Return fake IP address
|
||||||
|
"""
|
||||||
|
return [self.my_ip]
|
||||||
|
|
||||||
|
def flags(self):
|
||||||
|
"""
|
||||||
|
Return a QFlags enum with IsUp and IsRunning
|
||||||
|
"""
|
||||||
|
return (QNetworkInterface.IsUp | QNetworkInterface.IsRunning)
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return self.my_name
|
||||||
|
|
||||||
|
def isValid(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class TestInterfaces(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
A test suite to test out functions/methods that use network interface(s).
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create an instance and a few example actions.
|
||||||
|
"""
|
||||||
|
self.build_settings()
|
||||||
|
if not hasattr(self, 'fake_lo'):
|
||||||
|
# Since these shouldn't change, only need to instantiate them the first time
|
||||||
|
self.fake_lo = FakeIP4InterfaceEntry()
|
||||||
|
self.fake_localhost = FakeIP4InterfaceEntry(name='localhost')
|
||||||
|
self.fake_address = FakeIP4InterfaceEntry(name='eth25')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Clean up
|
||||||
|
"""
|
||||||
|
self.destroy_settings()
|
||||||
|
|
||||||
|
@patch.object(openlp.core.common, 'log')
|
||||||
|
def test_ip4_no_interfaces(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test no interfaces available
|
||||||
|
"""
|
||||||
|
# GIVEN: Test environment
|
||||||
|
call_debug = [call('Getting local IPv4 interface(es) information')]
|
||||||
|
call_warning = [call('No active IPv4 network interfaces detected')]
|
||||||
|
|
||||||
|
# WHEN: get_local_ip4 is called
|
||||||
|
with patch('openlp.core.common.QNetworkInterface') as mock_network_interface:
|
||||||
|
mock_network_interface.allInterfaces.return_value = []
|
||||||
|
ifaces = get_local_ip4()
|
||||||
|
|
||||||
|
# THEN: There should not be any interfaces detected
|
||||||
|
mock_log.debug.assert_has_calls(call_debug)
|
||||||
|
mock_log.warning.assert_has_calls(call_warning)
|
||||||
|
assert not ifaces, 'There should have been no active interfaces listed'
|
||||||
|
|
||||||
|
@patch.object(openlp.core.common, 'log')
|
||||||
|
def test_ip4_lo(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test get_local_ip4 returns proper dictionary with 'lo'
|
||||||
|
"""
|
||||||
|
# GIVEN: Test environment
|
||||||
|
call_debug = [call('Getting local IPv4 interface(es) information'),
|
||||||
|
call('Checking for isValid and flags == IsUP | IsRunning'),
|
||||||
|
call('Checking address(es) protocol'),
|
||||||
|
call('Checking for protocol == IPv4Protocol'),
|
||||||
|
call('Getting interface information'),
|
||||||
|
call('Adding lo to active list')]
|
||||||
|
call_warning = [call('No active IPv4 interfaces found except localhost')]
|
||||||
|
|
||||||
|
# WHEN: get_local_ip4 is called
|
||||||
|
with patch('openlp.core.common.QNetworkInterface') as mock_network_interface:
|
||||||
|
mock_network_interface.allInterfaces.return_value = [self.fake_lo]
|
||||||
|
ifaces = get_local_ip4()
|
||||||
|
|
||||||
|
# THEN: There should be a fake 'lo' interface
|
||||||
|
mock_log.debug.assert_has_calls(call_debug)
|
||||||
|
mock_log.warning.assert_has_calls(call_warning)
|
||||||
|
assert ifaces == self.fake_lo.fake_data, "There should have been an 'lo' interface listed"
|
||||||
|
|
||||||
|
@patch.object(openlp.core.common, 'log')
|
||||||
|
def test_ip4_localhost(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test get_local_ip4 returns proper dictionary with 'lo' if interface is 'localhost'
|
||||||
|
"""
|
||||||
|
# GIVEN: Test environment
|
||||||
|
call_debug = [call('Getting local IPv4 interface(es) information'),
|
||||||
|
call('Checking for isValid and flags == IsUP | IsRunning'),
|
||||||
|
call('Checking address(es) protocol'),
|
||||||
|
call('Checking for protocol == IPv4Protocol'),
|
||||||
|
call('Getting interface information'),
|
||||||
|
call('Adding localhost to active list'),
|
||||||
|
call('Renaming windows localhost to lo')]
|
||||||
|
call_warning = [call('No active IPv4 interfaces found except localhost')]
|
||||||
|
|
||||||
|
# WHEN: get_local_ip4 is called
|
||||||
|
with patch('openlp.core.common.QNetworkInterface') as mock_network_interface:
|
||||||
|
mock_network_interface.allInterfaces.return_value = [self.fake_localhost]
|
||||||
|
ifaces = get_local_ip4()
|
||||||
|
|
||||||
|
# THEN: There should be a fake 'lo' interface
|
||||||
|
mock_log.debug.assert_has_calls(call_debug)
|
||||||
|
mock_log.warning.assert_has_calls(call_warning)
|
||||||
|
assert ifaces == self.fake_lo.fake_data, "There should have been an 'lo' interface listed"
|
||||||
|
|
||||||
|
@patch.object(openlp.core.common, 'log')
|
||||||
|
def test_ip4_eth25(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test get_local_ip4 returns proper dictionary with 'eth25'
|
||||||
|
"""
|
||||||
|
# GIVEN: Test environment
|
||||||
|
call_debug = [call('Getting local IPv4 interface(es) information'),
|
||||||
|
call('Checking for isValid and flags == IsUP | IsRunning'),
|
||||||
|
call('Checking address(es) protocol'),
|
||||||
|
call('Checking for protocol == IPv4Protocol'),
|
||||||
|
call('Getting interface information'),
|
||||||
|
call('Adding eth25 to active list')]
|
||||||
|
call_warning = []
|
||||||
|
|
||||||
|
# WHEN: get_local_ip4 is called
|
||||||
|
with patch('openlp.core.common.QNetworkInterface') as mock_network_interface:
|
||||||
|
mock_network_interface.allInterfaces.return_value = [self.fake_address]
|
||||||
|
ifaces = get_local_ip4()
|
||||||
|
|
||||||
|
# THEN: There should be a fake 'eth25' interface
|
||||||
|
mock_log.debug.assert_has_calls(call_debug)
|
||||||
|
mock_log.warning.assert_has_calls(call_warning)
|
||||||
|
assert ifaces == self.fake_address.fake_data
|
||||||
|
|
||||||
|
@patch.object(openlp.core.common, 'log')
|
||||||
|
def test_ip4_lo_eth25(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test get_local_ip4 returns proper dictionary with 'eth25'
|
||||||
|
"""
|
||||||
|
# GIVEN: Test environment
|
||||||
|
call_debug = [call('Getting local IPv4 interface(es) information'),
|
||||||
|
call('Checking for isValid and flags == IsUP | IsRunning'),
|
||||||
|
call('Checking address(es) protocol'),
|
||||||
|
call('Checking for protocol == IPv4Protocol'),
|
||||||
|
call('Getting interface information'),
|
||||||
|
call('Adding lo to active list'),
|
||||||
|
call('Checking for isValid and flags == IsUP | IsRunning'),
|
||||||
|
call('Checking address(es) protocol'),
|
||||||
|
call('Checking for protocol == IPv4Protocol'),
|
||||||
|
call('Getting interface information'),
|
||||||
|
call('Adding eth25 to active list'),
|
||||||
|
call('Found at least one IPv4 interface, removing localhost')]
|
||||||
|
call_warning = []
|
||||||
|
|
||||||
|
# WHEN: get_local_ip4 is called
|
||||||
|
with patch('openlp.core.common.QNetworkInterface') as mock_network_interface:
|
||||||
|
mock_network_interface.allInterfaces.return_value = [self.fake_lo, self.fake_address]
|
||||||
|
ifaces = get_local_ip4()
|
||||||
|
|
||||||
|
# THEN: There should be a fake 'eth25' interface
|
||||||
|
mock_log.debug.assert_has_calls(call_debug)
|
||||||
|
mock_log.warning.assert_has_calls(call_warning)
|
||||||
|
assert ifaces == self.fake_address.fake_data, "There should have been only 'eth25' interface listed"
|
@ -4,7 +4,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Copyright (c) 2008-2017 OpenLP Developers #
|
# Copyright (c) 2008-2018 OpenLP Developers #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# This program is free software; you can redistribute it and/or modify it #
|
# 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 #
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
@ -20,5 +20,5 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
Module-level functions for the projector test suite
|
:mod tests/openlp_core/projectors: Tests for projector code
|
||||||
"""
|
"""
|
||||||
|
@ -28,15 +28,45 @@ from unittest import TestCase
|
|||||||
from unittest.mock import call, patch
|
from unittest.mock import call, patch
|
||||||
|
|
||||||
import openlp.core.projectors.pjlink
|
import openlp.core.projectors.pjlink
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.projectors.constants import PJLINK_PORT
|
from openlp.core.projectors.constants import PJLINK_PORT
|
||||||
from openlp.core.projectors.pjlink import PJLinkUDP
|
from openlp.core.projectors.pjlink import PJLinkUDP
|
||||||
|
from openlp.core.projectors.tab import ProjectorTab
|
||||||
|
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
from tests.resources.projector.data import TEST1_DATA
|
from tests.resources.projector.data import TEST1_DATA
|
||||||
|
|
||||||
|
|
||||||
class TestPJLinkBase(TestCase):
|
class TestPJLinkBase(TestCase, TestMixin):
|
||||||
"""
|
"""
|
||||||
Tests for the PJLinkUDP class
|
Tests for the PJLinkUDP class
|
||||||
"""
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create the UI and setup necessary options
|
||||||
|
"""
|
||||||
|
self.setup_application()
|
||||||
|
self.build_settings()
|
||||||
|
Registry.create()
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.projectors.db.init_url') as mocked_init_url:
|
||||||
|
if os.path.exists(TEST_DB):
|
||||||
|
os.unlink(TEST_DB)
|
||||||
|
mocked_init_url.return_value = 'sqlite:///%s' % TEST_DB
|
||||||
|
self.projectordb = ProjectorDB()
|
||||||
|
if not hasattr(self, 'projector_manager'):
|
||||||
|
self.projector_manager = ProjectorManager(projectordb=self.projectordb)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Remove test database.
|
||||||
|
Delete all the C++ objects at the end so that we don't have a segfault.
|
||||||
|
"""
|
||||||
|
# self.projectordb.session.close()
|
||||||
|
self.destroy_settings()
|
||||||
|
# del self.projector_manager
|
||||||
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
@patch.object(openlp.core.projectors.pjlink, 'log')
|
||||||
def test_get_datagram_data_negative_zero_length(self, mock_log):
|
def test_get_datagram_data_negative_zero_length(self, mock_log):
|
||||||
"""
|
"""
|
||||||
@ -44,9 +74,9 @@ class TestPJLinkBase(TestCase):
|
|||||||
"""
|
"""
|
||||||
# GIVEN: Test setup
|
# GIVEN: Test setup
|
||||||
pjlink_udp = PJLinkUDP()
|
pjlink_udp = PJLinkUDP()
|
||||||
log_warning_calls = [call('(UDP) No data (-1)')]
|
log_warning_calls = [call('(UDP:4352) No data (-1)')]
|
||||||
log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'),
|
log_debug_calls = [call('(UDP:4352) PJLinkUDP() Initialized'),
|
||||||
call('(UDP) get_datagram() - Receiving data')]
|
call('(UDP:4352) get_datagram() - Receiving data')]
|
||||||
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \
|
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \
|
||||||
patch.object(pjlink_udp, 'readDatagram') as mock_read:
|
patch.object(pjlink_udp, 'readDatagram') as mock_read:
|
||||||
mock_datagram.return_value = -1
|
mock_datagram.return_value = -1
|
||||||
@ -66,9 +96,9 @@ class TestPJLinkBase(TestCase):
|
|||||||
"""
|
"""
|
||||||
# GIVEN: Test setup
|
# GIVEN: Test setup
|
||||||
pjlink_udp = PJLinkUDP()
|
pjlink_udp = PJLinkUDP()
|
||||||
log_warning_calls = [call('(UDP) get_datagram() called when pending data size is 0')]
|
log_warning_calls = [call('(UDP:4352) get_datagram() called when pending data size is 0')]
|
||||||
log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'),
|
log_debug_calls = [call('(UDP:4352) PJLinkUDP() Initialized'),
|
||||||
call('(UDP) get_datagram() - Receiving data')]
|
call('(UDP:4352) get_datagram() - Receiving data')]
|
||||||
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \
|
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \
|
||||||
patch.object(pjlink_udp, 'readDatagram') as mock_read:
|
patch.object(pjlink_udp, 'readDatagram') as mock_read:
|
||||||
mock_datagram.return_value = 0
|
mock_datagram.return_value = 0
|
||||||
@ -88,9 +118,9 @@ class TestPJLinkBase(TestCase):
|
|||||||
"""
|
"""
|
||||||
# GIVEN: Test setup
|
# GIVEN: Test setup
|
||||||
pjlink_udp = PJLinkUDP()
|
pjlink_udp = PJLinkUDP()
|
||||||
log_warning_calls = [call('(UDP) get_datagram() called when pending data size is 0')]
|
log_warning_calls = [call('(UDP:4352) get_datagram() called when pending data size is 0')]
|
||||||
log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'),
|
log_debug_calls = [call('(UDP:4352) PJLinkUDP() Initialized'),
|
||||||
call('(UDP) get_datagram() - Receiving data')]
|
call('(UDP:4352) get_datagram() - Receiving data')]
|
||||||
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram:
|
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram:
|
||||||
mock_datagram.return_value = 0
|
mock_datagram.return_value = 0
|
||||||
|
|
||||||
@ -100,3 +130,147 @@ class TestPJLinkBase(TestCase):
|
|||||||
# THEN: Log entries should be made and method returns
|
# THEN: Log entries should be made and method returns
|
||||||
mock_log.warning.assert_has_calls(log_warning_calls)
|
mock_log.warning.assert_has_calls(log_warning_calls)
|
||||||
mock_log.debug.assert_has_calls(log_debug_calls)
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
|
||||||
|
@patch.object(openlp.core.projectors.tab, 'log')
|
||||||
|
def test_pjlinksettings_add_udp_listener(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test adding UDP listners to PJLink Settings tab
|
||||||
|
"""
|
||||||
|
# GIVEN: Initial setup
|
||||||
|
log_debug_calls = [call('PJLink settings tab initialized'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([4352])')]
|
||||||
|
log_warning_calls = []
|
||||||
|
|
||||||
|
pjlink_udp = PJLinkUDP()
|
||||||
|
settings_tab = ProjectorTab(parent=None)
|
||||||
|
|
||||||
|
# WHEN: add_udp_listener is called with single port
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp.port, callback=pjlink_udp.check_settings)
|
||||||
|
|
||||||
|
# THEN: settings tab should have one entry
|
||||||
|
assert len(settings_tab.udp_listeners) == 1
|
||||||
|
assert pjlink_udp.port in settings_tab.udp_listeners
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_calls)
|
||||||
|
|
||||||
|
@patch.object(openlp.core.projectors.tab, 'log')
|
||||||
|
def test_pjlinksettings_add_udp_listener_multiple_same(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test adding second UDP listner with same port to PJLink Settings tab
|
||||||
|
"""
|
||||||
|
# GIVEN: Initial setup
|
||||||
|
log_debug_calls = [call('PJLink settings tab initialized'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([4352])')]
|
||||||
|
log_warning_calls = [call('Port 4352 already in list - not adding')]
|
||||||
|
pjlink_udp = PJLinkUDP()
|
||||||
|
settings_tab = ProjectorTab(parent=None)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp.port, callback=pjlink_udp.check_settings)
|
||||||
|
|
||||||
|
# WHEN: add_udp_listener is called with second instance same port
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp.port, callback=pjlink_udp.check_settings)
|
||||||
|
|
||||||
|
# THEN: settings tab should have one entry
|
||||||
|
assert len(settings_tab.udp_listeners) == 1
|
||||||
|
assert pjlink_udp.port in settings_tab.udp_listeners
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_calls)
|
||||||
|
|
||||||
|
@patch.object(openlp.core.projectors.tab, 'log')
|
||||||
|
def test_pjlinksettings_add_udp_listener_multiple_different(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test adding second UDP listner with different port to PJLink Settings tab
|
||||||
|
"""
|
||||||
|
# GIVEN: Initial setup
|
||||||
|
log_debug_calls = [call('PJLink settings tab initialized'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([4352])')]
|
||||||
|
log_warning_calls = []
|
||||||
|
|
||||||
|
settings_tab = ProjectorTab(parent=None)
|
||||||
|
pjlink_udp1 = PJLinkUDP(port=4352)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp1.port, callback=pjlink_udp1.check_settings)
|
||||||
|
|
||||||
|
# WHEN: add_udp_listener is called with second instance different port
|
||||||
|
pjlink_udp2 = PJLinkUDP(port=4353)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp2.port, callback=pjlink_udp2.check_settings)
|
||||||
|
|
||||||
|
# THEN: settings tab should have two entry
|
||||||
|
assert len(settings_tab.udp_listeners) == 2
|
||||||
|
assert pjlink_udp1.port in settings_tab.udp_listeners
|
||||||
|
assert pjlink_udp2.port in settings_tab.udp_listeners
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_calls)
|
||||||
|
|
||||||
|
@patch.object(openlp.core.projectors.tab, 'log')
|
||||||
|
def test_pjlinksettings_remove_udp_listener(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test removing UDP listners to PJLink Settings tab
|
||||||
|
"""
|
||||||
|
# GIVEN: Initial setup
|
||||||
|
log_debug_calls = [call('PJLink settings tab initialized'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([4352])'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([])')]
|
||||||
|
log_warning_calls = []
|
||||||
|
|
||||||
|
pjlink_udp = PJLinkUDP()
|
||||||
|
settings_tab = ProjectorTab(parent=None)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp.port, callback=pjlink_udp.check_settings)
|
||||||
|
|
||||||
|
# WHEN: remove_udp_listener is called with single port
|
||||||
|
settings_tab.remove_udp_listener(port=pjlink_udp.port)
|
||||||
|
|
||||||
|
# THEN: settings tab should have one entry
|
||||||
|
assert len(settings_tab.udp_listeners) == 0
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_calls)
|
||||||
|
|
||||||
|
@patch.object(openlp.core.projectors.tab, 'log')
|
||||||
|
def test_pjlinksettings_remove_udp_listener_multiple_different(self, mock_log):
|
||||||
|
"""
|
||||||
|
Test adding second UDP listner with different port to PJLink Settings tab
|
||||||
|
"""
|
||||||
|
# GIVEN: Initial setup
|
||||||
|
log_debug_calls = [call('PJLink settings tab initialized'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([4352])')]
|
||||||
|
log_warning_calls = []
|
||||||
|
|
||||||
|
settings_tab = ProjectorTab(parent=None)
|
||||||
|
pjlink_udp1 = PJLinkUDP(port=4352)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp1.port, callback=pjlink_udp1.check_settings)
|
||||||
|
pjlink_udp2 = PJLinkUDP(port=4353)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp2.port, callback=pjlink_udp2.check_settings)
|
||||||
|
|
||||||
|
# WHEN: remove_udp_listener called for one port
|
||||||
|
settings_tab.remove_udp_listener(port=4353)
|
||||||
|
|
||||||
|
# THEN: settings tab should have one entry
|
||||||
|
assert len(settings_tab.udp_listeners) == 1
|
||||||
|
assert pjlink_udp1.port in settings_tab.udp_listeners
|
||||||
|
assert pjlink_udp2.port not in settings_tab.udp_listeners
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_calls)
|
||||||
|
|
||||||
|
@patch.object(PJLinkUDP, 'check_settings')
|
||||||
|
@patch.object(openlp.core.projectors.pjlink, 'log')
|
||||||
|
@patch.object(openlp.core.projectors.tab, 'log')
|
||||||
|
def test_pjlinksettings_call_udp_listener(self, mock_tab_log, mock_pjlink_log, mock_check_settings):
|
||||||
|
"""
|
||||||
|
Test calling UDP listners in PJLink Settings tab
|
||||||
|
"""
|
||||||
|
# GIVEN: Initial setup
|
||||||
|
tab_debug_calls = [call('PJLink settings tab initialized'),
|
||||||
|
call('PJLinkSettings: new callback list: dict_keys([4352])'),
|
||||||
|
call('PJLinkSettings: Calling UDP listeners')]
|
||||||
|
pjlink_debug_calls = [call.debug('(UDP:4352) PJLinkUDP() Initialized')]
|
||||||
|
|
||||||
|
pjlink_udp = PJLinkUDP()
|
||||||
|
settings_tab = ProjectorTab(parent=None)
|
||||||
|
settings_tab.add_udp_listener(port=pjlink_udp.port, callback=pjlink_udp.check_settings)
|
||||||
|
|
||||||
|
# WHEN: calling UDP listener via registry
|
||||||
|
settings_tab.call_udp_listener()
|
||||||
|
|
||||||
|
# THEN: settings tab should have one entry
|
||||||
|
assert len(settings_tab.udp_listeners) == 1
|
||||||
|
mock_check_settings.assert_called()
|
||||||
|
mock_tab_log.debug.assert_has_calls(tab_debug_calls)
|
||||||
|
mock_pjlink_log.assert_has_calls(pjlink_debug_calls)
|
||||||
|
Binary file not shown.
BIN
tests/resources/bibles/web-bible-2.4.6-proxy-meta-v1.sqlite
Normal file
BIN
tests/resources/bibles/web-bible-2.4.6-proxy-meta-v1.sqlite
Normal file
Binary file not shown.
BIN
tests/resources/bibles/web-bible-2.4.6-v1.sqlite
Normal file
BIN
tests/resources/bibles/web-bible-2.4.6-v1.sqlite
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user