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
|
||||
"""
|
||||
# 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',
|
||||
help='Disable the error notification form.')
|
||||
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
|
||||
|
@ -60,7 +60,6 @@ def get_local_ip4():
|
||||
|
||||
: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')
|
||||
my_ip4 = {}
|
||||
for iface in QNetworkInterface.allInterfaces():
|
||||
@ -70,8 +69,6 @@ def get_local_ip4():
|
||||
log.debug('Checking address(es) protocol')
|
||||
for address in iface.addressEntries():
|
||||
ip = address.ip()
|
||||
# NOTE: Next line will skip if interface is localhost - keep for now until we decide about it later
|
||||
# if (ip.protocol() == QAbstractSocket.IPv4Protocol) and (ip != QHostAddress.LocalHost):
|
||||
log.debug('Checking for protocol == IPv4Protocol')
|
||||
if ip.protocol() == QAbstractSocket.IPv4Protocol:
|
||||
log.debug('Getting interface information')
|
||||
@ -83,12 +80,13 @@ def get_local_ip4():
|
||||
ip.toIPv4Address()).toString()
|
||||
}
|
||||
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:
|
||||
log.debug('Renaming windows localhost to lo')
|
||||
my_ip4['lo'] = my_ip4['localhost']
|
||||
my_ip4.pop('localhost')
|
||||
if len(my_ip4) == 0:
|
||||
log.warning('No active IPv4 network interfaces detected')
|
||||
if len(my_ip4) == 1:
|
||||
if 'lo' in my_ip4:
|
||||
# No active interfaces - so leave localhost in there
|
||||
|
@ -26,19 +26,14 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import appdirs
|
||||
|
||||
import openlp
|
||||
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.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__)
|
||||
|
||||
FROZEN_APP_PATH = Path(sys.argv[0]).parent
|
||||
@ -144,8 +139,10 @@ def _get_os_dir_path(dir_type):
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
return Path(openlp.__file__).parent
|
||||
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:
|
||||
return openlp_folder_path / 'Data'
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
@ -153,15 +150,15 @@ def _get_os_dir_path(dir_type):
|
||||
return openlp_folder_path
|
||||
else:
|
||||
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():
|
||||
return directory
|
||||
return Path('/usr', 'share', 'openlp')
|
||||
if XDG_BASE_AVAILABLE:
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return Path(BaseDirectory.xdg_data_home, 'openlp')
|
||||
elif dir_type == AppLocation.CacheDir:
|
||||
return Path(BaseDirectory.xdg_cache_home, 'openlp')
|
||||
return Path(site_dirs[1])
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return Path(dirs.user_data_dir)
|
||||
elif dir_type == AppLocation.CacheDir:
|
||||
return Path(dirs.user_cache_dir)
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return Path(os.getenv('HOME'), '.openlp', 'data')
|
||||
return Path(os.getenv('HOME'), '.openlp')
|
||||
|
@ -58,8 +58,7 @@ class Registry(object):
|
||||
registry.functions_list = {}
|
||||
registry.working_flags = {}
|
||||
# Allow the tests to remove Registry entries but not the live system
|
||||
registry.running_under_test = 'nose' in sys.argv[0]
|
||||
registry.running_under_test = 'pytest' in sys.argv[0]
|
||||
registry.running_under_test = 'nose' in sys.argv[0] or 'pytest' in sys.argv[0]
|
||||
registry.initialising = True
|
||||
return registry
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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/poll time': 20, # PJLink timeout is 30 seconds
|
||||
'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__ = ''
|
||||
# Settings upgrades prior to 3.0
|
||||
@ -306,7 +307,11 @@ class Settings(QtCore.QSettings):
|
||||
('songuasge/db database', 'songusage/db database', []),
|
||||
('presentations / Powerpoint Viewer', '', []),
|
||||
(['core/monitor', 'core/x position', 'core/y position', 'core/height', 'core/width', 'core/override',
|
||||
'core/display on monitor'], 'core/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
|
||||
|
@ -399,4 +399,4 @@ def create_separated_list(string_list):
|
||||
last=string_list[-1])
|
||||
else:
|
||||
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.
|
||||
"""
|
||||
log.debug('accept_me() signal received')
|
||||
valid = True
|
||||
if len(self.name_text.text().strip()) < 1:
|
||||
QtWidgets.QMessageBox.warning(self,
|
||||
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.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.lib.ui import create_widget_action
|
||||
from openlp.core.projectors import DialogSourceStyle
|
||||
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT, \
|
||||
E_UNKNOWN_SOCKET_ERROR, PJLINK_PORT, QSOCKET_STATE, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, \
|
||||
S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG
|
||||
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT,\
|
||||
E_UNKNOWN_SOCKET_ERROR, QSOCKET_STATE, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, S_NOT_CONNECTED, S_OFF,\
|
||||
S_ON, S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG
|
||||
|
||||
from openlp.core.projectors.db import ProjectorDB
|
||||
from openlp.core.projectors.editform import ProjectorEditForm
|
||||
from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
|
||||
@ -297,7 +298,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
||||
self.projector_list = []
|
||||
self.source_select_form = None
|
||||
# Dictionary of PJLinkUDP objects to listen for UDP broadcasts from PJLink 2+ projectors.
|
||||
# Key is port number that projectors use
|
||||
# Key is port number
|
||||
self.pjlink_udp = {}
|
||||
# Dict for matching projector status to display icon
|
||||
self.status_icons = {
|
||||
@ -335,10 +336,6 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
||||
"""
|
||||
Post-initialize setups.
|
||||
"""
|
||||
# Default PJLink port UDP socket
|
||||
log.debug('Creating PJLinkUDP listener for default port {port}'.format(port=PJLINK_PORT))
|
||||
self.pjlink_udp = {PJLINK_PORT: PJLinkUDP(port=PJLINK_PORT)}
|
||||
self.pjlink_udp[PJLINK_PORT].bind(PJLINK_PORT)
|
||||
# Set 1.5 second delay before loading all projectors
|
||||
if self.autostart:
|
||||
log.debug('Delaying 1.5 seconds before loading all projectors')
|
||||
@ -351,6 +348,36 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
||||
self.projector_form.editProjector.connect(self.edit_projector_from_wizard)
|
||||
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):
|
||||
"""
|
||||
Retrieve the saved settings
|
||||
@ -518,25 +545,22 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
try:
|
||||
projector.poll_timer.stop()
|
||||
projector.poll_timer.timeout.disconnect(projector.link.poll_loop)
|
||||
projector.link.poll_timer.stop()
|
||||
projector.link.poll_timer.timeout.disconnect(projector.link.poll_loop)
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
try:
|
||||
projector.socket_timer.stop()
|
||||
projector.socket_timer.timeout.disconnect(projector.link.socket_abort)
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
# Disconnect signals from projector being deleted
|
||||
try:
|
||||
self.pjlink_udp[projector.link.port].data_received.disconnect(projector.link.get_buffer)
|
||||
projector.link.socket_timer.stop()
|
||||
projector.link.socket_timer.timeout.disconnect(projector.link.socket_abort)
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
old_port = projector.link.port
|
||||
# Rebuild projector list
|
||||
new_list = []
|
||||
for item in self.projector_list:
|
||||
if item.link.db_item.id == projector.link.db_item.id:
|
||||
log.debug('Removing projector "{item}"'.format(item=item.link.name))
|
||||
continue
|
||||
new_list.append(item)
|
||||
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))
|
||||
for item in self.projector_list:
|
||||
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):
|
||||
"""
|
||||
@ -748,15 +773,8 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
||||
item.link.projectorAuthentication.connect(self.authentication_error)
|
||||
item.link.projectorNoAuthentication.connect(self.no_authentication_error)
|
||||
item.link.projectorUpdateIcons.connect(self.update_icons)
|
||||
# Connect UDP signal to projector instances with same port
|
||||
if item.link.port not in self.pjlink_udp:
|
||||
log.debug('Adding new PJLinkUDP listener fo port {port}'.format(port=item.link.port))
|
||||
self.pjlink_udp[item.link.port] = PJLinkUDP(port=item.link.port)
|
||||
self.pjlink_udp[item.link.port].bind(item.link.port)
|
||||
log.debug('Connecting PJLinkUDP port {port} signal to "{item}"'.format(port=item.link.port,
|
||||
item=item.link.name))
|
||||
self.pjlink_udp[item.link.port].data_received.connect(item.link.get_buffer)
|
||||
|
||||
# Add UDP listener for new projector port
|
||||
self.udp_listen_add(item.link.port)
|
||||
self.projector_list.append(item)
|
||||
if start:
|
||||
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
|
||||
"""
|
||||
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.ip = projector.ip
|
||||
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.notes = projector.notes
|
||||
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):
|
||||
"""'
|
||||
|
@ -99,32 +99,51 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
|
||||
self.search_active = False
|
||||
self.search_time = 30000 # 30 seconds for allowed time
|
||||
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)
|
||||
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()
|
||||
def get_datagram(self):
|
||||
"""
|
||||
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()
|
||||
if -1 == read_size:
|
||||
log.warning('(UDP) No data (-1)')
|
||||
log.warning('(UDP:{port}) No data (-1)'.format(port=self.port))
|
||||
return
|
||||
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
|
||||
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
|
||||
data_in, peer_host, peer_port = self.readDatagram(read_size)
|
||||
data = data_in.decode('utf-8') if isinstance(data_in, bytes) else data_in
|
||||
log.debug('(UDP) {size} bytes received from {adx} on port {port}'.format(size=len(data),
|
||||
adx=peer_host.toString(),
|
||||
port=self.port))
|
||||
log.debug('(UDP) packet "{data}"'.format(data=data))
|
||||
log.debug('(UDP) Sending data_received signal to projectors')
|
||||
log.debug('(UDP:{port}) {size} bytes received from {adx}'.format(size=len(data),
|
||||
adx=peer_host.toString(),
|
||||
port=self.port))
|
||||
log.debug('(UDP:{port}) packet "{data}"'.format(data=data, port=self.port))
|
||||
log.debug('(UDP:{port}) Sending data_received signal to projectors'.format(port=self.port))
|
||||
self.data_received.emit(peer_host, self.localPort(), data)
|
||||
return
|
||||
|
||||
@ -144,6 +163,25 @@ class PJLinkUDP(QtNetwork.QUdpSocket):
|
||||
self.search_active = False
|
||||
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):
|
||||
"""
|
||||
|
@ -27,6 +27,7 @@ import logging
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from openlp.core.common.i18n import UiStrings, translate
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib.settingstab import SettingsTab
|
||||
from openlp.core.projectors import DialogSourceStyle
|
||||
@ -48,8 +49,11 @@ class ProjectorTab(SettingsTab):
|
||||
:param parent: Parent widget
|
||||
"""
|
||||
self.icon_path = UiIcons().projector
|
||||
self.udp_listeners = {} # Key on port number
|
||||
projector_translated = translate('OpenLP.ProjectorTab', 'Projector')
|
||||
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):
|
||||
"""
|
||||
@ -91,6 +95,10 @@ class ProjectorTab(SettingsTab):
|
||||
self.connect_box_layout.addRow(self.dialog_type_label, self.dialog_type_combo_box)
|
||||
self.left_layout.addStretch()
|
||||
self.dialog_type_combo_box.activated.connect(self.on_dialog_type_combo_box_changed)
|
||||
# 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)
|
||||
self.connect_on_linkup = QtWidgets.QCheckBox(self.connect_box)
|
||||
self.connect_on_linkup.setObjectName('connect_on_linkup')
|
||||
@ -117,6 +125,9 @@ class ProjectorTab(SettingsTab):
|
||||
translate('OpenLP.ProjectorTab', 'Single dialog box'))
|
||||
self.connect_on_linkup.setText(
|
||||
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):
|
||||
"""
|
||||
@ -126,6 +137,7 @@ class ProjectorTab(SettingsTab):
|
||||
self.socket_timeout_spin_box.setValue(Settings().value('projector/socket timeout'))
|
||||
self.socket_poll_spin_box.setValue(Settings().value('projector/poll time'))
|
||||
self.dialog_type_combo_box.setCurrentIndex(Settings().value('projector/source dialog type'))
|
||||
self.udp_broadcast_listen.setChecked(Settings().value('projector/udp broadcast listen'))
|
||||
self.connect_on_linkup.setChecked(Settings().value('projector/connect when LKUP received'))
|
||||
|
||||
def save(self):
|
||||
@ -137,6 +149,41 @@ class ProjectorTab(SettingsTab):
|
||||
Settings().setValue('projector/poll time', self.socket_poll_spin_box.value())
|
||||
Settings().setValue('projector/source dialog type', self.dialog_type_combo_box.currentIndex())
|
||||
Settings().setValue('projector/connect when LKUP received', self.connect_on_linkup.isChecked())
|
||||
Settings().setValue('projector/udp broadcast listen', self.udp_broadcast_listen.isChecked())
|
||||
self.call_udp_listener()
|
||||
|
||||
def on_dialog_type_combo_box_changed(self):
|
||||
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',
|
||||
'Jonathan "springermac" Springer', 'Philip "Phill" Ridout']
|
||||
contributors = ['Stuart "sibecker" Becker', 'Gerald "jerryb" Britton', 'Jonathan "gushie" Corwin',
|
||||
'Samuel "MrGamgee" Findlay', 'Michael "cocooncrash" Gorven', 'Scott "sguerrieri" Guerrieri',
|
||||
'Simon Hanna', 'Chris Hill',
|
||||
'Samuel "MrGamgee" Findlay', 'Bastian Germann', 'Michael "cocooncrash" Gorven',
|
||||
'Scott "sguerrieri" Guerrieri', 'Simon Hanna', 'Chris Hill',
|
||||
'Matthias "matthub" Hub', 'Meinert "m2j" Jordan', 'Ian Knightly'
|
||||
'Armin "orangeshirt" K\xf6hler',
|
||||
'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/second bibles': True,
|
||||
'bibles/primary bible': '',
|
||||
'bibles/proxy name': '',
|
||||
'bibles/proxy address': '',
|
||||
'bibles/proxy username': '',
|
||||
'bibles/proxy password': '',
|
||||
'bibles/bible theme': '',
|
||||
'bibles/verse 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.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
|
||||
self.select_stack.addWidget(self.open_song_widget)
|
||||
self.web_tab_widget = QtWidgets.QTabWidget(self.select_page)
|
||||
self.web_tab_widget.setObjectName('WebTabWidget')
|
||||
self.web_widget = QtWidgets.QWidget(self.select_page)
|
||||
self.web_widget.setObjectName('WebWidget')
|
||||
self.web_bible_tab = QtWidgets.QWidget()
|
||||
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_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_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_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_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.addItems(['', '', ''])
|
||||
self.web_source_combo_box.setEnabled(False)
|
||||
@ -245,31 +245,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.web_progress_bar.setObjectName('WebTranslationProgressBar')
|
||||
self.web_progress_bar.setVisible(False)
|
||||
self.web_bible_layout.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.web_progress_bar)
|
||||
self.web_tab_widget.addTab(self.web_bible_tab, '')
|
||||
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.select_stack.addWidget(self.web_widget)
|
||||
self.zefania_widget = QtWidgets.QWidget(self.select_page)
|
||||
self.zefania_widget.setObjectName('ZefaniaWidget')
|
||||
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',
|
||||
'Bibleserver'))
|
||||
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_folder_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD data folder:'))
|
||||
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_progress_bar.setVisible(True)
|
||||
self.web_progress_bar.setValue(0)
|
||||
proxy_server = self.field('proxy_server')
|
||||
# TODO: Where does critical_error_message_box get %s string from?
|
||||
for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract(proxy_server)),
|
||||
(WebDownload.BibleGateway, BGExtract(proxy_server)),
|
||||
(WebDownload.Bibleserver, BSExtract(proxy_server))):
|
||||
for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract()),
|
||||
(WebDownload.BibleGateway, BGExtract()),
|
||||
(WebDownload.Bibleserver, BSExtract())):
|
||||
try:
|
||||
bibles = extractor.get_bibles_from_http()
|
||||
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('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('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_copyright', self.copyright_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('web_location', WebDownload.Crosswalk)
|
||||
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.version_name_edit.setPlaceholderText(UiStrings().RequiredShowInFooter)
|
||||
self.setField('license_copyright', self.copyright_edit.text())
|
||||
@ -767,9 +728,6 @@ class BibleImportForm(OpenLPWizard):
|
||||
BibleFormat.WebDownload, name=license_version,
|
||||
download_source=WebDownload.Names[download_location],
|
||||
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
|
||||
)
|
||||
elif bible_type == BibleFormat.Zefania:
|
||||
|
@ -83,20 +83,19 @@ def init_schema(url):
|
||||
|
||||
meta_table = Table('metadata', metadata,
|
||||
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,
|
||||
Column('id', types.Integer, primary_key=True),
|
||||
Column('book_reference_id', types.Integer, index=True),
|
||||
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,
|
||||
Column('id', types.Integer, primary_key=True, index=True),
|
||||
Column('book_id', types.Integer, ForeignKey(
|
||||
'book.id'), index=True),
|
||||
Column('book_id', types.Integer, ForeignKey('book.id'), index=True),
|
||||
Column('chapter', types.Integer, index=True),
|
||||
Column('verse', types.Integer, index=True),
|
||||
Column('text', types.UnicodeText, index=True),)
|
||||
Column('text', types.UnicodeText, index=True))
|
||||
|
||||
try:
|
||||
class_mapper(BibleMeta)
|
||||
|
@ -95,9 +95,8 @@ class BGExtract(RegistryProperties):
|
||||
"""
|
||||
NAME = 'BibleGateway'
|
||||
|
||||
def __init__(self, proxy_url=None):
|
||||
log.debug('BGExtract.init(proxy_url="{url}")'.format(url=proxy_url))
|
||||
self.proxy_url = proxy_url
|
||||
def __init__(self):
|
||||
log.debug('BGExtract.__init__()')
|
||||
socket.setdefaulttimeout(30)
|
||||
|
||||
def _remove_elements(self, parent, tag, class_=None):
|
||||
@ -359,9 +358,8 @@ class BSExtract(RegistryProperties):
|
||||
"""
|
||||
NAME = 'BibleServer'
|
||||
|
||||
def __init__(self, proxy_url=None):
|
||||
log.debug('BSExtract.init("{url}")'.format(url=proxy_url))
|
||||
self.proxy_url = proxy_url
|
||||
def __init__(self):
|
||||
log.debug('BSExtract.__init__()')
|
||||
socket.setdefaulttimeout(30)
|
||||
|
||||
def get_bible_chapter(self, version, book_name, chapter):
|
||||
@ -462,9 +460,8 @@ class CWExtract(RegistryProperties):
|
||||
"""
|
||||
NAME = 'Crosswalk'
|
||||
|
||||
def __init__(self, proxy_url=None):
|
||||
log.debug('CWExtract.init("{url}")'.format(url=proxy_url))
|
||||
self.proxy_url = proxy_url
|
||||
def __init__(self):
|
||||
log.debug('CWExtract.__init__()')
|
||||
socket.setdefaulttimeout(30)
|
||||
|
||||
def get_bible_chapter(self, version, book_name, chapter):
|
||||
@ -596,19 +593,9 @@ class HTTPBible(BibleImport, RegistryProperties):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.download_source = kwargs['download_source']
|
||||
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
|
||||
if 'path' in kwargs:
|
||||
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:
|
||||
self.language_id = kwargs['language_id']
|
||||
|
||||
@ -622,20 +609,12 @@ class HTTPBible(BibleImport, RegistryProperties):
|
||||
'Registering Bible and loading books...'))
|
||||
self.save_meta('download_source', self.download_source)
|
||||
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':
|
||||
handler = CWExtract(self.proxy_server)
|
||||
handler = CWExtract()
|
||||
elif self.download_source.lower() == 'biblegateway':
|
||||
handler = BGExtract(self.proxy_server)
|
||||
handler = BGExtract()
|
||||
elif self.download_source.lower() == 'bibleserver':
|
||||
handler = BSExtract(self.proxy_server)
|
||||
handler = BSExtract()
|
||||
books = handler.get_books_from_http(self.download_name)
|
||||
if not books:
|
||||
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('source = {source}'.format(source=self.download_source))
|
||||
if self.download_source.lower() == 'crosswalk':
|
||||
handler = CWExtract(self.proxy_server)
|
||||
handler = CWExtract()
|
||||
elif self.download_source.lower() == 'biblegateway':
|
||||
handler = BGExtract(self.proxy_server)
|
||||
handler = BGExtract()
|
||||
elif self.download_source.lower() == 'bibleserver':
|
||||
handler = BSExtract(self.proxy_server)
|
||||
handler = BSExtract()
|
||||
return handler.get_bible_chapter(self.download_name, book, chapter)
|
||||
|
||||
def get_books(self):
|
||||
|
@ -118,7 +118,6 @@ class BibleManager(LogMixin, RegistryProperties):
|
||||
self.web = 'Web'
|
||||
self.db_cache = None
|
||||
self.path = AppLocation.get_section_data_path(self.settings_section)
|
||||
self.proxy_name = Settings().value(self.settings_section + '/proxy name')
|
||||
self.suffix = '.sqlite'
|
||||
self.import_wizard = None
|
||||
self.reload_bibles()
|
||||
@ -151,11 +150,8 @@ class BibleManager(LogMixin, RegistryProperties):
|
||||
if self.db_cache[name].is_web_bible:
|
||||
source = self.db_cache[name].get_object(BibleMeta, 'download_source')
|
||||
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,
|
||||
download_name=download_name)
|
||||
if meta_proxy:
|
||||
web_bible.proxy_server = meta_proxy.value
|
||||
self.db_cache[name] = web_bible
|
||||
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
|
||||
|
||||
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__)
|
||||
__version__ = 1
|
||||
__version__ = 2
|
||||
|
||||
|
||||
# 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.
|
||||
"""
|
||||
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.group_combobox = QtWidgets.QComboBox(choose_group_dialog)
|
||||
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.new_radio_button = QtWidgets.QRadioButton(choose_group_dialog)
|
||||
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.new_group_edit = QtWidgets.QLineEdit(choose_group_dialog)
|
||||
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.group_button_box = create_button_box(choose_group_dialog, 'buttonBox', ['ok'])
|
||||
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.existing_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'Existing 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()):
|
||||
if self.group_combobox.itemData(index) == selected_group:
|
||||
self.group_combobox.setCurrentIndex(index)
|
||||
self.existing_radio_button.setChecked(True)
|
||||
return QtWidgets.QDialog.exec(self)
|
||||
|
@ -430,16 +430,6 @@ class ImageMediaItem(MediaManagerItem):
|
||||
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
|
||||
preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
|
||||
# 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:
|
||||
self.choose_group_form.existing_radio_button.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'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def start():
|
||||
"""
|
||||
Instantiate and run the application.
|
||||
"""
|
||||
@ -60,3 +60,7 @@ if __name__ == '__main__':
|
||||
if is_macosx():
|
||||
sys.argv = [x for x in sys.argv if not x.startswith('-psn')]
|
||||
main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start()
|
@ -11,11 +11,8 @@ environment:
|
||||
|
||||
install:
|
||||
# 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"
|
||||
# Install mysql dependency
|
||||
- "%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 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"
|
||||
# Download and install pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)
|
||||
- "%PYTHON%\\python.exe -m pip install https://get.openlp.org/win-sdk/PyICU-1.9.5-cp34-cp34m-win32.whl"
|
||||
# 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
|
||||
|
@ -33,25 +33,18 @@ import os
|
||||
import sys
|
||||
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_LIN = sys.platform.startswith('lin')
|
||||
IS_MAC = sys.platform.startswith('dar')
|
||||
|
||||
|
||||
VERS = {
|
||||
'Python': '3.4',
|
||||
'Python': '3.6',
|
||||
'PyQt5': '5.0',
|
||||
'Qt5': '5.0',
|
||||
'pymediainfo': '2.2',
|
||||
'sqlalchemy': '0.5',
|
||||
# pyenchant 1.6 required on Windows
|
||||
'enchant': '1.6' if IS_WIN else '1.3'
|
||||
'enchant': '1.6'
|
||||
}
|
||||
|
||||
# pywin32
|
||||
@ -59,7 +52,6 @@ WIN32_MODULES = [
|
||||
'win32com',
|
||||
'win32ui',
|
||||
'pywintypes',
|
||||
'pyodbc',
|
||||
'icu',
|
||||
]
|
||||
|
||||
@ -85,19 +77,16 @@ MODULES = [
|
||||
'PyQt5.QtTest',
|
||||
'PyQt5.QtWebKit',
|
||||
'PyQt5.QtMultimedia',
|
||||
'pymediainfo',
|
||||
'appdirs',
|
||||
'sqlalchemy',
|
||||
'alembic',
|
||||
'sqlite3',
|
||||
'lxml',
|
||||
'chardet',
|
||||
'enchant',
|
||||
'bs4',
|
||||
'mako',
|
||||
'uno',
|
||||
'websockets',
|
||||
'asyncio',
|
||||
'waitress',
|
||||
'six',
|
||||
'webob',
|
||||
'requests',
|
||||
'qtawesome'
|
||||
@ -105,12 +94,17 @@ MODULES = [
|
||||
|
||||
|
||||
OPTIONAL_MODULES = [
|
||||
('mysql.connector', '(MySQL support)', True),
|
||||
('psycopg2', '(PostgreSQL support)', True),
|
||||
('nose2', '(testing framework)', True),
|
||||
('mock', '(testing module)', sys.version_info[1] < 3),
|
||||
('jenkins', '(access jenkins api - package name: jenkins-webapi)', True),
|
||||
('pysword', '(import SWORD bibles)', True),
|
||||
('mysql.connector', '(MySQL support)'),
|
||||
('pyodbc', '(ODBC support)'),
|
||||
('psycopg2', '(PostgreSQL support)'),
|
||||
('enchant', '(spell checker)'),
|
||||
('pysword', '(import SWORD bibles)'),
|
||||
('uno', '(LibreOffice/OpenOffice support)'),
|
||||
# development/testing modules
|
||||
('jenkins', '(access jenkins api)'),
|
||||
('launchpadlib', '(launchpad script support)'),
|
||||
('nose2', '(testing framework)'),
|
||||
('pylint', '(linter)')
|
||||
]
|
||||
|
||||
w = sys.stdout.write
|
||||
@ -239,8 +233,7 @@ def main():
|
||||
check_module(m)
|
||||
print('Checking for 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:
|
||||
print('Checking for Windows specific modules...')
|
||||
for m in WIN32_MODULES:
|
||||
|
63
setup.py
63
setup.py
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
@ -21,9 +22,10 @@
|
||||
###############################################################################
|
||||
|
||||
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'
|
||||
@ -110,6 +112,34 @@ except Exception:
|
||||
finally:
|
||||
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(
|
||||
name='OpenLP',
|
||||
@ -157,18 +187,25 @@ using a computer and a data projector.""",
|
||||
keywords='open source church presentation lyrics projection song bible display project',
|
||||
author='Raoul Snyman',
|
||||
author_email='raoulsnyman@openlp.org',
|
||||
url='http://openlp.org/',
|
||||
url='https://openlp.org/',
|
||||
license='GNU General Public License',
|
||||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
|
||||
scripts=['openlp.py'],
|
||||
packages=find_packages(exclude=['ez_setup', 'tests']),
|
||||
py_modules=['run_openlp'],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=[
|
||||
# -*- Extra requirements: -*-
|
||||
'sqlalchemy',
|
||||
'alembic'
|
||||
],
|
||||
entry_points="""
|
||||
# -*- Entry points: -*-
|
||||
"""
|
||||
python_requires='>=3.6',
|
||||
install_requires=requires,
|
||||
extras_require={
|
||||
'mysql': ['mysql-connector-python'],
|
||||
'odbc': ['pyodbc'],
|
||||
'postgresql': ['psycopg2'],
|
||||
'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:
|
||||
|
||||
- Mock
|
||||
- Nose
|
||||
- pytest
|
||||
- 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.
|
||||
|
||||
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::
|
||||
|
||||
nosetests -v tests
|
||||
pytest -v tests
|
||||
|
||||
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::
|
||||
|
||||
nosetests -v tests/functional/test_applocation.py
|
||||
|
||||
Finally, to only run a particular test, run the following command::
|
||||
|
||||
nosetests -v tests/functional/test_applocation.py:TestAppLocation.get_frozen_path_test
|
||||
pytest -v tests/functional/openlp_core/test_app.py
|
||||
|
@ -162,6 +162,7 @@ def test_check_same_instance():
|
||||
def test_get_language_from_settings():
|
||||
assert LanguageManager.get_language() == 'en'
|
||||
|
||||
|
||||
def test_get_language_from_settings_returns_unchanged_if_unknown_format():
|
||||
Settings().setValue('core/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 #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 #
|
||||
# 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
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
|
||||
|
||||
import openlp.core.projectors.pjlink
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.projectors.constants import PJLINK_PORT
|
||||
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
|
||||
|
||||
|
||||
class TestPJLinkBase(TestCase):
|
||||
class TestPJLinkBase(TestCase, TestMixin):
|
||||
"""
|
||||
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')
|
||||
def test_get_datagram_data_negative_zero_length(self, mock_log):
|
||||
"""
|
||||
@ -44,9 +74,9 @@ class TestPJLinkBase(TestCase):
|
||||
"""
|
||||
# GIVEN: Test setup
|
||||
pjlink_udp = PJLinkUDP()
|
||||
log_warning_calls = [call('(UDP) No data (-1)')]
|
||||
log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'),
|
||||
call('(UDP) get_datagram() - Receiving data')]
|
||||
log_warning_calls = [call('(UDP:4352) No data (-1)')]
|
||||
log_debug_calls = [call('(UDP:4352) PJLinkUDP() Initialized'),
|
||||
call('(UDP:4352) get_datagram() - Receiving data')]
|
||||
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \
|
||||
patch.object(pjlink_udp, 'readDatagram') as mock_read:
|
||||
mock_datagram.return_value = -1
|
||||
@ -66,9 +96,9 @@ class TestPJLinkBase(TestCase):
|
||||
"""
|
||||
# GIVEN: Test setup
|
||||
pjlink_udp = PJLinkUDP()
|
||||
log_warning_calls = [call('(UDP) get_datagram() called when pending data size is 0')]
|
||||
log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'),
|
||||
call('(UDP) get_datagram() - Receiving data')]
|
||||
log_warning_calls = [call('(UDP:4352) get_datagram() called when pending data size is 0')]
|
||||
log_debug_calls = [call('(UDP:4352) PJLinkUDP() Initialized'),
|
||||
call('(UDP:4352) get_datagram() - Receiving data')]
|
||||
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \
|
||||
patch.object(pjlink_udp, 'readDatagram') as mock_read:
|
||||
mock_datagram.return_value = 0
|
||||
@ -88,9 +118,9 @@ class TestPJLinkBase(TestCase):
|
||||
"""
|
||||
# GIVEN: Test setup
|
||||
pjlink_udp = PJLinkUDP()
|
||||
log_warning_calls = [call('(UDP) get_datagram() called when pending data size is 0')]
|
||||
log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'),
|
||||
call('(UDP) get_datagram() - Receiving data')]
|
||||
log_warning_calls = [call('(UDP:4352) get_datagram() called when pending data size is 0')]
|
||||
log_debug_calls = [call('(UDP:4352) PJLinkUDP() Initialized'),
|
||||
call('(UDP:4352) get_datagram() - Receiving data')]
|
||||
with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram:
|
||||
mock_datagram.return_value = 0
|
||||
|
||||
@ -100,3 +130,147 @@ class TestPJLinkBase(TestCase):
|
||||
# THEN: Log entries should be made and method returns
|
||||
mock_log.warning.assert_has_calls(log_warning_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