forked from openlp/openlp
HEAD
This commit is contained in:
commit
9752716672
@ -305,6 +305,7 @@ class Settings(QtCore.QSettings):
|
|||||||
(u'bibles/bookname language', u'bibles/book name language', []),
|
(u'bibles/bookname language', u'bibles/book name language', []),
|
||||||
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
|
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
|
||||||
(u'songs/ccli number', u'general/ccli number', []),
|
(u'songs/ccli number', u'general/ccli number', []),
|
||||||
|
(u'media/use phonon', u'', []),
|
||||||
# Changed during 2.1.x development.
|
# Changed during 2.1.x development.
|
||||||
(u'advanced/stylesheet fix', u'', []),
|
(u'advanced/stylesheet fix', u'', []),
|
||||||
(u'bibles/last directory 1', u'bibles/last directory import', []),
|
(u'bibles/last directory 1', u'bibles/last directory import', []),
|
||||||
|
@ -69,6 +69,14 @@ try:
|
|||||||
MAKO_VERSION = mako.__version__
|
MAKO_VERSION = mako.__version__
|
||||||
except ImportError:
|
except ImportError:
|
||||||
MAKO_VERSION = u'-'
|
MAKO_VERSION = u'-'
|
||||||
|
try:
|
||||||
|
import icu
|
||||||
|
try:
|
||||||
|
ICU_VERSION = icu.VERSION
|
||||||
|
except AttributeError:
|
||||||
|
ICU_VERSION = u'OK'
|
||||||
|
except ImportError:
|
||||||
|
ICU_VERSION = u'-'
|
||||||
try:
|
try:
|
||||||
import uno
|
import uno
|
||||||
arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue')
|
arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue')
|
||||||
@ -143,6 +151,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
|||||||
u'PyEnchant: %s\n' % ENCHANT_VERSION + \
|
u'PyEnchant: %s\n' % ENCHANT_VERSION + \
|
||||||
u'PySQLite: %s\n' % SQLITE_VERSION + \
|
u'PySQLite: %s\n' % SQLITE_VERSION + \
|
||||||
u'Mako: %s\n' % MAKO_VERSION + \
|
u'Mako: %s\n' % MAKO_VERSION + \
|
||||||
|
u'pyICU: %s\n' % ICU_VERSION + \
|
||||||
u'pyUNO bridge: %s\n' % UNO_VERSION + \
|
u'pyUNO bridge: %s\n' % UNO_VERSION + \
|
||||||
u'VLC: %s\n' % VLC_VERSION
|
u'VLC: %s\n' % VLC_VERSION
|
||||||
if platform.system() == u'Linux':
|
if platform.system() == u'Linux':
|
||||||
|
227
openlp/core/ui/media/vendor/vlc.py
vendored
227
openlp/core/ui/media/vendor/vlc.py
vendored
@ -48,7 +48,7 @@ import sys
|
|||||||
from inspect import getargspec
|
from inspect import getargspec
|
||||||
|
|
||||||
__version__ = "N/A"
|
__version__ = "N/A"
|
||||||
build_date = "Thu Mar 21 22:33:03 2013"
|
build_date = "Mon Apr 1 23:47:38 2013"
|
||||||
|
|
||||||
if sys.version_info[0] > 2:
|
if sys.version_info[0] > 2:
|
||||||
str = str
|
str = str
|
||||||
@ -70,7 +70,7 @@ if sys.version_info[0] > 2:
|
|||||||
if isinstance(b, bytes):
|
if isinstance(b, bytes):
|
||||||
return b.decode(sys.getfilesystemencoding())
|
return b.decode(sys.getfilesystemencoding())
|
||||||
else:
|
else:
|
||||||
return str(b)
|
return b
|
||||||
else:
|
else:
|
||||||
str = str
|
str = str
|
||||||
unicode = unicode
|
unicode = unicode
|
||||||
@ -278,6 +278,11 @@ def class_result(classname):
|
|||||||
return classname(result)
|
return classname(result)
|
||||||
return wrap_errcheck
|
return wrap_errcheck
|
||||||
|
|
||||||
|
# Wrapper for the opaque struct libvlc_log_t
|
||||||
|
class Log(ctypes.Structure):
|
||||||
|
pass
|
||||||
|
Log_ptr = ctypes.POINTER(Log)
|
||||||
|
|
||||||
# FILE* ctypes wrapper, copied from
|
# FILE* ctypes wrapper, copied from
|
||||||
# http://svn.python.org/projects/ctypes/trunk/ctypeslib/ctypeslib/contrib/pythonhdr.py
|
# http://svn.python.org/projects/ctypes/trunk/ctypeslib/ctypeslib/contrib/pythonhdr.py
|
||||||
class FILE(ctypes.Structure):
|
class FILE(ctypes.Structure):
|
||||||
@ -675,11 +680,14 @@ class Callback(ctypes.c_void_p):
|
|||||||
pass
|
pass
|
||||||
class LogCb(ctypes.c_void_p):
|
class LogCb(ctypes.c_void_p):
|
||||||
"""Callback prototype for LibVLC log message handler.
|
"""Callback prototype for LibVLC log message handler.
|
||||||
\param data data pointer as given to L{libvlc_log_subscribe}()
|
\param data data pointer as given to L{libvlc_log_set}()
|
||||||
\param level message level (@ref enum libvlc_log_level)
|
\param level message level (@ref enum libvlc_log_level)
|
||||||
|
\param ctx message context (meta-informations about the message)
|
||||||
\param fmt printf() format string (as defined by ISO C11)
|
\param fmt printf() format string (as defined by ISO C11)
|
||||||
\param args variable argument list for the format
|
\param args variable argument list for the format
|
||||||
\note Log message handlers <b>must</b> be thread-safe.
|
\note Log message handlers <b>must</b> be thread-safe.
|
||||||
|
\warning The message context pointer, the format string parameters and the
|
||||||
|
variable arguments are only valid until the callback returns.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
class VideoLockCb(ctypes.c_void_p):
|
class VideoLockCb(ctypes.c_void_p):
|
||||||
@ -813,13 +821,16 @@ class CallbackDecorators(object):
|
|||||||
Callback.__doc__ = '''Callback function notification
|
Callback.__doc__ = '''Callback function notification
|
||||||
\param p_event the event triggering the callback
|
\param p_event the event triggering the callback
|
||||||
'''
|
'''
|
||||||
LogCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p)
|
LogCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, Log_ptr, ctypes.c_char_p, ctypes.c_void_p)
|
||||||
LogCb.__doc__ = '''Callback prototype for LibVLC log message handler.
|
LogCb.__doc__ = '''Callback prototype for LibVLC log message handler.
|
||||||
\param data data pointer as given to L{libvlc_log_subscribe}()
|
\param data data pointer as given to L{libvlc_log_set}()
|
||||||
\param level message level (@ref enum libvlc_log_level)
|
\param level message level (@ref enum libvlc_log_level)
|
||||||
|
\param ctx message context (meta-informations about the message)
|
||||||
\param fmt printf() format string (as defined by ISO C11)
|
\param fmt printf() format string (as defined by ISO C11)
|
||||||
\param args variable argument list for the format
|
\param args variable argument list for the format
|
||||||
\note Log message handlers <b>must</b> be thread-safe.
|
\note Log message handlers <b>must</b> be thread-safe.
|
||||||
|
\warning The message context pointer, the format string parameters and the
|
||||||
|
variable arguments are only valid until the callback returns.
|
||||||
'''
|
'''
|
||||||
VideoLockCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ListPOINTER(ctypes.c_void_p))
|
VideoLockCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ListPOINTER(ctypes.c_void_p))
|
||||||
VideoLockCb.__doc__ = '''Callback prototype to allocate and lock a picture buffer.
|
VideoLockCb.__doc__ = '''Callback prototype to allocate and lock a picture buffer.
|
||||||
@ -1407,7 +1418,7 @@ class Instance(_Ctype):
|
|||||||
@param name: interface name, or NULL for default.
|
@param name: interface name, or NULL for default.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_add_intf(self, name)
|
return libvlc_add_intf(self, str_to_bytes(name))
|
||||||
|
|
||||||
def set_user_agent(self, name, http):
|
def set_user_agent(self, name, http):
|
||||||
'''Sets the application name. LibVLC passes this as the user agent string
|
'''Sets the application name. LibVLC passes this as the user agent string
|
||||||
@ -1416,7 +1427,33 @@ class Instance(_Ctype):
|
|||||||
@param http: HTTP User Agent, e.g. "FooBar/1.2.3 Python/2.6.0".
|
@param http: HTTP User Agent, e.g. "FooBar/1.2.3 Python/2.6.0".
|
||||||
@version: LibVLC 1.1.1 or later.
|
@version: LibVLC 1.1.1 or later.
|
||||||
'''
|
'''
|
||||||
return libvlc_set_user_agent(self, name, http)
|
return libvlc_set_user_agent(self, str_to_bytes(name), str_to_bytes(http))
|
||||||
|
|
||||||
|
def log_unset(self):
|
||||||
|
'''Unsets the logging callback for a LibVLC instance. This is rarely needed:
|
||||||
|
the callback is implicitly unset when the instance is destroyed.
|
||||||
|
This function will wait for any pending callbacks invocation to complete
|
||||||
|
(causing a deadlock if called from within the callback).
|
||||||
|
@version: LibVLC 2.1.0 or later.
|
||||||
|
'''
|
||||||
|
return libvlc_log_unset(self)
|
||||||
|
|
||||||
|
def log_set(self, data, p_instance):
|
||||||
|
'''Sets the logging callback for a LibVLC instance.
|
||||||
|
This function is thread-safe: it will wait for any pending callbacks
|
||||||
|
invocation to complete.
|
||||||
|
@param data: opaque data pointer for the callback function @note Some log messages (especially debug) are emitted by LibVLC while is being initialized. These messages cannot be captured with this interface. @warning A deadlock may occur if this function is called from the callback.
|
||||||
|
@param p_instance: libvlc instance.
|
||||||
|
@version: LibVLC 2.1.0 or later.
|
||||||
|
'''
|
||||||
|
return libvlc_log_set(self, data, p_instance)
|
||||||
|
|
||||||
|
def log_set_file(self, stream):
|
||||||
|
'''Sets up logging to a file.
|
||||||
|
@param stream: FILE pointer opened for writing (the FILE pointer must remain valid until L{log_unset}()).
|
||||||
|
@version: LibVLC 2.1.0 or later.
|
||||||
|
'''
|
||||||
|
return libvlc_log_set_file(self, stream)
|
||||||
|
|
||||||
def media_new_location(self, psz_mrl):
|
def media_new_location(self, psz_mrl):
|
||||||
'''Create a media with a certain given media resource location,
|
'''Create a media with a certain given media resource location,
|
||||||
@ -1429,7 +1466,7 @@ class Instance(_Ctype):
|
|||||||
@param psz_mrl: the media location.
|
@param psz_mrl: the media location.
|
||||||
@return: the newly created media or NULL on error.
|
@return: the newly created media or NULL on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_media_new_location(self, psz_mrl)
|
return libvlc_media_new_location(self, str_to_bytes(psz_mrl))
|
||||||
|
|
||||||
def media_new_path(self, path):
|
def media_new_path(self, path):
|
||||||
'''Create a media for a certain file path.
|
'''Create a media for a certain file path.
|
||||||
@ -1437,7 +1474,7 @@ class Instance(_Ctype):
|
|||||||
@param path: local filesystem path.
|
@param path: local filesystem path.
|
||||||
@return: the newly created media or NULL on error.
|
@return: the newly created media or NULL on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_media_new_path(self, path)
|
return libvlc_media_new_path(self, str_to_bytes(path))
|
||||||
|
|
||||||
def media_new_fd(self, fd):
|
def media_new_fd(self, fd):
|
||||||
'''Create a media for an already open file descriptor.
|
'''Create a media for an already open file descriptor.
|
||||||
@ -1465,14 +1502,14 @@ class Instance(_Ctype):
|
|||||||
@param psz_name: the name of the node.
|
@param psz_name: the name of the node.
|
||||||
@return: the new empty media or NULL on error.
|
@return: the new empty media or NULL on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_media_new_as_node(self, psz_name)
|
return libvlc_media_new_as_node(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def media_discoverer_new_from_name(self, psz_name):
|
def media_discoverer_new_from_name(self, psz_name):
|
||||||
'''Discover media service by name.
|
'''Discover media service by name.
|
||||||
@param psz_name: service name.
|
@param psz_name: service name.
|
||||||
@return: media discover object or NULL in case of error.
|
@return: media discover object or NULL in case of error.
|
||||||
'''
|
'''
|
||||||
return libvlc_media_discoverer_new_from_name(self, psz_name)
|
return libvlc_media_discoverer_new_from_name(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def media_library_new(self):
|
def media_library_new(self):
|
||||||
'''Create an new Media Library object.
|
'''Create an new Media Library object.
|
||||||
@ -1500,7 +1537,7 @@ class Instance(_Ctype):
|
|||||||
@return: A NULL-terminated linked list of potential audio output devices. It must be freed it with L{audio_output_device_list_release}().
|
@return: A NULL-terminated linked list of potential audio output devices. It must be freed it with L{audio_output_device_list_release}().
|
||||||
@version: LibVLC 2.1.0 or later.
|
@version: LibVLC 2.1.0 or later.
|
||||||
'''
|
'''
|
||||||
return libvlc_audio_output_device_list_get(self, aout)
|
return libvlc_audio_output_device_list_get(self, str_to_bytes(aout))
|
||||||
|
|
||||||
def vlm_release(self):
|
def vlm_release(self):
|
||||||
'''Release the vlm instance related to the given L{Instance}.
|
'''Release the vlm instance related to the given L{Instance}.
|
||||||
@ -1518,7 +1555,7 @@ class Instance(_Ctype):
|
|||||||
@param b_loop: Should this broadcast be played in loop ?
|
@param b_loop: Should this broadcast be played in loop ?
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_add_broadcast(self, psz_name, psz_input, psz_output, i_options, ppsz_options, b_enabled, b_loop)
|
return libvlc_vlm_add_broadcast(self, str_to_bytes(psz_name), str_to_bytes(psz_input), str_to_bytes(psz_output), i_options, ppsz_options, b_enabled, b_loop)
|
||||||
|
|
||||||
def vlm_add_vod(self, psz_name, psz_input, i_options, ppsz_options, b_enabled, psz_mux):
|
def vlm_add_vod(self, psz_name, psz_input, i_options, ppsz_options, b_enabled, psz_mux):
|
||||||
'''Add a vod, with one input.
|
'''Add a vod, with one input.
|
||||||
@ -1530,14 +1567,14 @@ class Instance(_Ctype):
|
|||||||
@param psz_mux: the muxer of the vod media.
|
@param psz_mux: the muxer of the vod media.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_add_vod(self, psz_name, psz_input, i_options, ppsz_options, b_enabled, psz_mux)
|
return libvlc_vlm_add_vod(self, str_to_bytes(psz_name), str_to_bytes(psz_input), i_options, ppsz_options, b_enabled, str_to_bytes(psz_mux))
|
||||||
|
|
||||||
def vlm_del_media(self, psz_name):
|
def vlm_del_media(self, psz_name):
|
||||||
'''Delete a media (VOD or broadcast).
|
'''Delete a media (VOD or broadcast).
|
||||||
@param psz_name: the media to delete.
|
@param psz_name: the media to delete.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_del_media(self, psz_name)
|
return libvlc_vlm_del_media(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def vlm_set_enabled(self, psz_name, b_enabled):
|
def vlm_set_enabled(self, psz_name, b_enabled):
|
||||||
'''Enable or disable a media (VOD or broadcast).
|
'''Enable or disable a media (VOD or broadcast).
|
||||||
@ -1545,7 +1582,7 @@ class Instance(_Ctype):
|
|||||||
@param b_enabled: the new status.
|
@param b_enabled: the new status.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_set_enabled(self, psz_name, b_enabled)
|
return libvlc_vlm_set_enabled(self, str_to_bytes(psz_name), b_enabled)
|
||||||
|
|
||||||
def vlm_set_output(self, psz_name, psz_output):
|
def vlm_set_output(self, psz_name, psz_output):
|
||||||
'''Set the output for a media.
|
'''Set the output for a media.
|
||||||
@ -1553,7 +1590,7 @@ class Instance(_Ctype):
|
|||||||
@param psz_output: the output MRL (the parameter to the "sout" variable).
|
@param psz_output: the output MRL (the parameter to the "sout" variable).
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_set_output(self, psz_name, psz_output)
|
return libvlc_vlm_set_output(self, str_to_bytes(psz_name), str_to_bytes(psz_output))
|
||||||
|
|
||||||
def vlm_set_input(self, psz_name, psz_input):
|
def vlm_set_input(self, psz_name, psz_input):
|
||||||
'''Set a media's input MRL. This will delete all existing inputs and
|
'''Set a media's input MRL. This will delete all existing inputs and
|
||||||
@ -1562,7 +1599,7 @@ class Instance(_Ctype):
|
|||||||
@param psz_input: the input MRL.
|
@param psz_input: the input MRL.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_set_input(self, psz_name, psz_input)
|
return libvlc_vlm_set_input(self, str_to_bytes(psz_name), str_to_bytes(psz_input))
|
||||||
|
|
||||||
def vlm_add_input(self, psz_name, psz_input):
|
def vlm_add_input(self, psz_name, psz_input):
|
||||||
'''Add a media's input MRL. This will add the specified one.
|
'''Add a media's input MRL. This will add the specified one.
|
||||||
@ -1570,7 +1607,7 @@ class Instance(_Ctype):
|
|||||||
@param psz_input: the input MRL.
|
@param psz_input: the input MRL.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_add_input(self, psz_name, psz_input)
|
return libvlc_vlm_add_input(self, str_to_bytes(psz_name), str_to_bytes(psz_input))
|
||||||
|
|
||||||
def vlm_set_loop(self, psz_name, b_loop):
|
def vlm_set_loop(self, psz_name, b_loop):
|
||||||
'''Set a media's loop status.
|
'''Set a media's loop status.
|
||||||
@ -1578,7 +1615,7 @@ class Instance(_Ctype):
|
|||||||
@param b_loop: the new status.
|
@param b_loop: the new status.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_set_loop(self, psz_name, b_loop)
|
return libvlc_vlm_set_loop(self, str_to_bytes(psz_name), b_loop)
|
||||||
|
|
||||||
def vlm_set_mux(self, psz_name, psz_mux):
|
def vlm_set_mux(self, psz_name, psz_mux):
|
||||||
'''Set a media's vod muxer.
|
'''Set a media's vod muxer.
|
||||||
@ -1586,7 +1623,7 @@ class Instance(_Ctype):
|
|||||||
@param psz_mux: the new muxer.
|
@param psz_mux: the new muxer.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_set_mux(self, psz_name, psz_mux)
|
return libvlc_vlm_set_mux(self, str_to_bytes(psz_name), str_to_bytes(psz_mux))
|
||||||
|
|
||||||
def vlm_change_media(self, psz_name, psz_input, psz_output, i_options, ppsz_options, b_enabled, b_loop):
|
def vlm_change_media(self, psz_name, psz_input, psz_output, i_options, ppsz_options, b_enabled, b_loop):
|
||||||
'''Edit the parameters of a media. This will delete all existing inputs and
|
'''Edit the parameters of a media. This will delete all existing inputs and
|
||||||
@ -1600,28 +1637,28 @@ class Instance(_Ctype):
|
|||||||
@param b_loop: Should this broadcast be played in loop ?
|
@param b_loop: Should this broadcast be played in loop ?
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_change_media(self, psz_name, psz_input, psz_output, i_options, ppsz_options, b_enabled, b_loop)
|
return libvlc_vlm_change_media(self, str_to_bytes(psz_name), str_to_bytes(psz_input), str_to_bytes(psz_output), i_options, ppsz_options, b_enabled, b_loop)
|
||||||
|
|
||||||
def vlm_play_media(self, psz_name):
|
def vlm_play_media(self, psz_name):
|
||||||
'''Play the named broadcast.
|
'''Play the named broadcast.
|
||||||
@param psz_name: the name of the broadcast.
|
@param psz_name: the name of the broadcast.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_play_media(self, psz_name)
|
return libvlc_vlm_play_media(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def vlm_stop_media(self, psz_name):
|
def vlm_stop_media(self, psz_name):
|
||||||
'''Stop the named broadcast.
|
'''Stop the named broadcast.
|
||||||
@param psz_name: the name of the broadcast.
|
@param psz_name: the name of the broadcast.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_stop_media(self, psz_name)
|
return libvlc_vlm_stop_media(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def vlm_pause_media(self, psz_name):
|
def vlm_pause_media(self, psz_name):
|
||||||
'''Pause the named broadcast.
|
'''Pause the named broadcast.
|
||||||
@param psz_name: the name of the broadcast.
|
@param psz_name: the name of the broadcast.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_pause_media(self, psz_name)
|
return libvlc_vlm_pause_media(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def vlm_seek_media(self, psz_name, f_percentage):
|
def vlm_seek_media(self, psz_name, f_percentage):
|
||||||
'''Seek in the named broadcast.
|
'''Seek in the named broadcast.
|
||||||
@ -1629,7 +1666,7 @@ class Instance(_Ctype):
|
|||||||
@param f_percentage: the percentage to seek to.
|
@param f_percentage: the percentage to seek to.
|
||||||
@return: 0 on success, -1 on error.
|
@return: 0 on success, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_seek_media(self, psz_name, f_percentage)
|
return libvlc_vlm_seek_media(self, str_to_bytes(psz_name), f_percentage)
|
||||||
|
|
||||||
def vlm_show_media(self, psz_name):
|
def vlm_show_media(self, psz_name):
|
||||||
'''Return information about the named media as a JSON
|
'''Return information about the named media as a JSON
|
||||||
@ -1643,7 +1680,7 @@ class Instance(_Ctype):
|
|||||||
@param psz_name: the name of the media, if the name is an empty string, all media is described.
|
@param psz_name: the name of the media, if the name is an empty string, all media is described.
|
||||||
@return: string with information about named media, or NULL on error.
|
@return: string with information about named media, or NULL on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_show_media(self, psz_name)
|
return libvlc_vlm_show_media(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def vlm_get_media_instance_position(self, psz_name, i_instance):
|
def vlm_get_media_instance_position(self, psz_name, i_instance):
|
||||||
'''Get vlm_media instance position by name or instance id.
|
'''Get vlm_media instance position by name or instance id.
|
||||||
@ -1651,7 +1688,7 @@ class Instance(_Ctype):
|
|||||||
@param i_instance: instance id.
|
@param i_instance: instance id.
|
||||||
@return: position as float or -1. on error.
|
@return: position as float or -1. on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_position(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_position(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_media_instance_time(self, psz_name, i_instance):
|
def vlm_get_media_instance_time(self, psz_name, i_instance):
|
||||||
'''Get vlm_media instance time by name or instance id.
|
'''Get vlm_media instance time by name or instance id.
|
||||||
@ -1659,7 +1696,7 @@ class Instance(_Ctype):
|
|||||||
@param i_instance: instance id.
|
@param i_instance: instance id.
|
||||||
@return: time as integer or -1 on error.
|
@return: time as integer or -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_time(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_time(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_media_instance_length(self, psz_name, i_instance):
|
def vlm_get_media_instance_length(self, psz_name, i_instance):
|
||||||
'''Get vlm_media instance length by name or instance id.
|
'''Get vlm_media instance length by name or instance id.
|
||||||
@ -1667,7 +1704,7 @@ class Instance(_Ctype):
|
|||||||
@param i_instance: instance id.
|
@param i_instance: instance id.
|
||||||
@return: length of media item or -1 on error.
|
@return: length of media item or -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_length(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_length(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_media_instance_rate(self, psz_name, i_instance):
|
def vlm_get_media_instance_rate(self, psz_name, i_instance):
|
||||||
'''Get vlm_media instance playback rate by name or instance id.
|
'''Get vlm_media instance playback rate by name or instance id.
|
||||||
@ -1675,7 +1712,7 @@ class Instance(_Ctype):
|
|||||||
@param i_instance: instance id.
|
@param i_instance: instance id.
|
||||||
@return: playback rate or -1 on error.
|
@return: playback rate or -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_rate(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_rate(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_media_instance_title(self, psz_name, i_instance):
|
def vlm_get_media_instance_title(self, psz_name, i_instance):
|
||||||
'''Get vlm_media instance title number by name or instance id.
|
'''Get vlm_media instance title number by name or instance id.
|
||||||
@ -1684,7 +1721,7 @@ class Instance(_Ctype):
|
|||||||
@return: title as number or -1 on error.
|
@return: title as number or -1 on error.
|
||||||
@bug: will always return 0.
|
@bug: will always return 0.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_title(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_title(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_media_instance_chapter(self, psz_name, i_instance):
|
def vlm_get_media_instance_chapter(self, psz_name, i_instance):
|
||||||
'''Get vlm_media instance chapter number by name or instance id.
|
'''Get vlm_media instance chapter number by name or instance id.
|
||||||
@ -1693,7 +1730,7 @@ class Instance(_Ctype):
|
|||||||
@return: chapter as number or -1 on error.
|
@return: chapter as number or -1 on error.
|
||||||
@bug: will always return 0.
|
@bug: will always return 0.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_chapter(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_chapter(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_media_instance_seekable(self, psz_name, i_instance):
|
def vlm_get_media_instance_seekable(self, psz_name, i_instance):
|
||||||
'''Is libvlc instance seekable ?
|
'''Is libvlc instance seekable ?
|
||||||
@ -1702,7 +1739,7 @@ class Instance(_Ctype):
|
|||||||
@return: 1 if seekable, 0 if not, -1 if media does not exist.
|
@return: 1 if seekable, 0 if not, -1 if media does not exist.
|
||||||
@bug: will always return 0.
|
@bug: will always return 0.
|
||||||
'''
|
'''
|
||||||
return libvlc_vlm_get_media_instance_seekable(self, psz_name, i_instance)
|
return libvlc_vlm_get_media_instance_seekable(self, str_to_bytes(psz_name), i_instance)
|
||||||
|
|
||||||
def vlm_get_event_manager(self):
|
def vlm_get_event_manager(self):
|
||||||
'''Get libvlc_event_manager from a vlm media.
|
'''Get libvlc_event_manager from a vlm media.
|
||||||
@ -1751,7 +1788,7 @@ class Media(_Ctype):
|
|||||||
self.add_option(o)
|
self.add_option(o)
|
||||||
|
|
||||||
|
|
||||||
def add_option(self, ppsz_options):
|
def add_option(self, psz_options):
|
||||||
'''Add an option to the media.
|
'''Add an option to the media.
|
||||||
This option will be used to determine how the media_player will
|
This option will be used to determine how the media_player will
|
||||||
read the media. This allows to use VLC's advanced
|
read the media. This allows to use VLC's advanced
|
||||||
@ -1763,11 +1800,11 @@ class Media(_Ctype):
|
|||||||
Specifically, due to architectural issues most audio and video options,
|
Specifically, due to architectural issues most audio and video options,
|
||||||
such as text renderer options, have no effects on an individual media.
|
such as text renderer options, have no effects on an individual media.
|
||||||
These options must be set through L{new}() instead.
|
These options must be set through L{new}() instead.
|
||||||
@param ppsz_options: the options (as a string).
|
@param psz_options: the options (as a string).
|
||||||
'''
|
'''
|
||||||
return libvlc_media_add_option(self, ppsz_options)
|
return libvlc_media_add_option(self, str_to_bytes(psz_options))
|
||||||
|
|
||||||
def add_option_flag(self, ppsz_options, i_flags):
|
def add_option_flag(self, psz_options, i_flags):
|
||||||
'''Add an option to the media with configurable flags.
|
'''Add an option to the media with configurable flags.
|
||||||
This option will be used to determine how the media_player will
|
This option will be used to determine how the media_player will
|
||||||
read the media. This allows to use VLC's advanced
|
read the media. This allows to use VLC's advanced
|
||||||
@ -1777,10 +1814,10 @@ class Media(_Ctype):
|
|||||||
specifically, due to architectural issues, video-related options
|
specifically, due to architectural issues, video-related options
|
||||||
such as text renderer options cannot be set on a single media. They
|
such as text renderer options cannot be set on a single media. They
|
||||||
must be set on the whole libvlc instance instead.
|
must be set on the whole libvlc instance instead.
|
||||||
@param ppsz_options: the options (as a string).
|
@param psz_options: the options (as a string).
|
||||||
@param i_flags: the flags for this option.
|
@param i_flags: the flags for this option.
|
||||||
'''
|
'''
|
||||||
return libvlc_media_add_option_flag(self, ppsz_options, i_flags)
|
return libvlc_media_add_option_flag(self, str_to_bytes(psz_options), i_flags)
|
||||||
|
|
||||||
def retain(self):
|
def retain(self):
|
||||||
'''Retain a reference to a media descriptor object (libvlc_media_t). Use
|
'''Retain a reference to a media descriptor object (libvlc_media_t). Use
|
||||||
@ -1829,7 +1866,7 @@ class Media(_Ctype):
|
|||||||
@param e_meta: the meta to write.
|
@param e_meta: the meta to write.
|
||||||
@param psz_value: the media's meta.
|
@param psz_value: the media's meta.
|
||||||
'''
|
'''
|
||||||
return libvlc_media_set_meta(self, e_meta, psz_value)
|
return libvlc_media_set_meta(self, e_meta, str_to_bytes(psz_value))
|
||||||
|
|
||||||
def save_meta(self):
|
def save_meta(self):
|
||||||
'''Save the meta previously set.
|
'''Save the meta previously set.
|
||||||
@ -2490,7 +2527,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@version: LibVLC 1.1.1 or later.
|
@version: LibVLC 1.1.1 or later.
|
||||||
@bug: All pixel planes are expected to have the same pitch. To use the YCbCr color space with chrominance subsampling, consider using L{video_set_format_callbacks}() instead.
|
@bug: All pixel planes are expected to have the same pitch. To use the YCbCr color space with chrominance subsampling, consider using L{video_set_format_callbacks}() instead.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_format(self, chroma, width, height, pitch)
|
return libvlc_video_set_format(self, str_to_bytes(chroma), width, height, pitch)
|
||||||
|
|
||||||
def video_set_format_callbacks(self, setup, cleanup):
|
def video_set_format_callbacks(self, setup, cleanup):
|
||||||
'''Set decoded video chroma and dimensions. This only works in combination with
|
'''Set decoded video chroma and dimensions. This only works in combination with
|
||||||
@ -2617,7 +2654,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@param channels: channels count.
|
@param channels: channels count.
|
||||||
@version: LibVLC 2.0.0 or later.
|
@version: LibVLC 2.0.0 or later.
|
||||||
'''
|
'''
|
||||||
return libvlc_audio_set_format(self, format, rate, channels)
|
return libvlc_audio_set_format(self, str_to_bytes(format), rate, channels)
|
||||||
|
|
||||||
def get_length(self):
|
def get_length(self):
|
||||||
'''Get the current movie length (in ms).
|
'''Get the current movie length (in ms).
|
||||||
@ -2843,7 +2880,7 @@ class MediaPlayer(_Ctype):
|
|||||||
'''Set new video aspect ratio.
|
'''Set new video aspect ratio.
|
||||||
@param psz_aspect: new video aspect-ratio or NULL to reset to default @note Invalid aspect ratios are ignored.
|
@param psz_aspect: new video aspect-ratio or NULL to reset to default @note Invalid aspect ratios are ignored.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_aspect_ratio(self, psz_aspect)
|
return libvlc_video_set_aspect_ratio(self, str_to_bytes(psz_aspect))
|
||||||
|
|
||||||
def video_get_spu(self):
|
def video_get_spu(self):
|
||||||
'''Get current video subtitle.
|
'''Get current video subtitle.
|
||||||
@ -2859,7 +2896,7 @@ class MediaPlayer(_Ctype):
|
|||||||
|
|
||||||
def video_set_spu(self, i_spu):
|
def video_set_spu(self, i_spu):
|
||||||
'''Set new video subtitle.
|
'''Set new video subtitle.
|
||||||
@param i_spu: new video subtitle to select.
|
@param i_spu: video subtitle track to select (i_id from track description).
|
||||||
@return: 0 on success, -1 if out of range.
|
@return: 0 on success, -1 if out of range.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_spu(self, i_spu)
|
return libvlc_video_set_spu(self, i_spu)
|
||||||
@ -2869,7 +2906,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@param psz_subtitle: new video subtitle file.
|
@param psz_subtitle: new video subtitle file.
|
||||||
@return: the success status (boolean).
|
@return: the success status (boolean).
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_subtitle_file(self, psz_subtitle)
|
return libvlc_video_set_subtitle_file(self, str_to_bytes(psz_subtitle))
|
||||||
|
|
||||||
def video_get_spu_delay(self):
|
def video_get_spu_delay(self):
|
||||||
'''Get the current subtitle delay. Positive values means subtitles are being
|
'''Get the current subtitle delay. Positive values means subtitles are being
|
||||||
@ -2900,7 +2937,7 @@ class MediaPlayer(_Ctype):
|
|||||||
'''Set new crop filter geometry.
|
'''Set new crop filter geometry.
|
||||||
@param psz_geometry: new crop filter geometry (NULL to unset).
|
@param psz_geometry: new crop filter geometry (NULL to unset).
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_crop_geometry(self, psz_geometry)
|
return libvlc_video_set_crop_geometry(self, str_to_bytes(psz_geometry))
|
||||||
|
|
||||||
def video_get_teletext(self):
|
def video_get_teletext(self):
|
||||||
'''Get current teletext page requested.
|
'''Get current teletext page requested.
|
||||||
@ -2948,13 +2985,13 @@ class MediaPlayer(_Ctype):
|
|||||||
@param i_height: the snapshot's height.
|
@param i_height: the snapshot's height.
|
||||||
@return: 0 on success, -1 if the video was not found.
|
@return: 0 on success, -1 if the video was not found.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_take_snapshot(self, num, psz_filepath, i_width, i_height)
|
return libvlc_video_take_snapshot(self, num, str_to_bytes(psz_filepath), i_width, i_height)
|
||||||
|
|
||||||
def video_set_deinterlace(self, psz_mode):
|
def video_set_deinterlace(self, psz_mode):
|
||||||
'''Enable or disable deinterlace filter.
|
'''Enable or disable deinterlace filter.
|
||||||
@param psz_mode: type of deinterlace filter, NULL to disable.
|
@param psz_mode: type of deinterlace filter, NULL to disable.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_deinterlace(self, psz_mode)
|
return libvlc_video_set_deinterlace(self, str_to_bytes(psz_mode))
|
||||||
|
|
||||||
def video_get_marquee_int(self, option):
|
def video_get_marquee_int(self, option):
|
||||||
'''Get an integer marquee option value.
|
'''Get an integer marquee option value.
|
||||||
@ -2982,7 +3019,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@param option: marq option to set See libvlc_video_marquee_string_option_t.
|
@param option: marq option to set See libvlc_video_marquee_string_option_t.
|
||||||
@param psz_text: marq option value.
|
@param psz_text: marq option value.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_marquee_string(self, option, psz_text)
|
return libvlc_video_set_marquee_string(self, option, str_to_bytes(psz_text))
|
||||||
|
|
||||||
def video_get_logo_int(self, option):
|
def video_get_logo_int(self, option):
|
||||||
'''Get integer logo option.
|
'''Get integer logo option.
|
||||||
@ -3006,7 +3043,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@param option: logo option to set, values of libvlc_video_logo_option_t.
|
@param option: logo option to set, values of libvlc_video_logo_option_t.
|
||||||
@param psz_value: logo option value.
|
@param psz_value: logo option value.
|
||||||
'''
|
'''
|
||||||
return libvlc_video_set_logo_string(self, option, psz_value)
|
return libvlc_video_set_logo_string(self, option, str_to_bytes(psz_value))
|
||||||
|
|
||||||
def video_get_adjust_int(self, option):
|
def video_get_adjust_int(self, option):
|
||||||
'''Get integer adjust option.
|
'''Get integer adjust option.
|
||||||
@ -3049,7 +3086,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@param psz_name: name of audio output, use psz_name of See L{AudioOutput}.
|
@param psz_name: name of audio output, use psz_name of See L{AudioOutput}.
|
||||||
@return: 0 if function succeded, -1 on error.
|
@return: 0 if function succeded, -1 on error.
|
||||||
'''
|
'''
|
||||||
return libvlc_audio_output_set(self, psz_name)
|
return libvlc_audio_output_set(self, str_to_bytes(psz_name))
|
||||||
|
|
||||||
def audio_output_device_set(self, psz_audio_output, psz_device_id):
|
def audio_output_device_set(self, psz_audio_output, psz_device_id):
|
||||||
'''Configures an explicit audio output device for a given audio output plugin.
|
'''Configures an explicit audio output device for a given audio output plugin.
|
||||||
@ -3065,7 +3102,7 @@ class MediaPlayer(_Ctype):
|
|||||||
@param psz_device_id: device.
|
@param psz_device_id: device.
|
||||||
@return: Nothing. Errors are ignored.
|
@return: Nothing. Errors are ignored.
|
||||||
'''
|
'''
|
||||||
return libvlc_audio_output_device_set(self, psz_audio_output, psz_device_id)
|
return libvlc_audio_output_device_set(self, str_to_bytes(psz_audio_output), str_to_bytes(psz_device_id))
|
||||||
|
|
||||||
def audio_toggle_mute(self):
|
def audio_toggle_mute(self):
|
||||||
'''Toggle mute status.
|
'''Toggle mute status.
|
||||||
@ -3314,44 +3351,43 @@ def libvlc_event_type_name(event_type):
|
|||||||
ctypes.c_char_p, ctypes.c_uint)
|
ctypes.c_char_p, ctypes.c_uint)
|
||||||
return f(event_type)
|
return f(event_type)
|
||||||
|
|
||||||
def libvlc_log_subscribe(sub, cb, data):
|
def libvlc_log_unset(p_instance):
|
||||||
'''Registers a logging callback to LibVLC.
|
'''Unsets the logging callback for a LibVLC instance. This is rarely needed:
|
||||||
This function is thread-safe.
|
the callback is implicitly unset when the instance is destroyed.
|
||||||
@param sub: uninitialized subscriber structure.
|
This function will wait for any pending callbacks invocation to complete
|
||||||
|
(causing a deadlock if called from within the callback).
|
||||||
|
@param p_instance: libvlc instance.
|
||||||
|
@version: LibVLC 2.1.0 or later.
|
||||||
|
'''
|
||||||
|
f = _Cfunctions.get('libvlc_log_unset', None) or \
|
||||||
|
_Cfunction('libvlc_log_unset', ((1,),), None,
|
||||||
|
None, Instance)
|
||||||
|
return f(p_instance)
|
||||||
|
|
||||||
|
def libvlc_log_set(cb, data, p_instance):
|
||||||
|
'''Sets the logging callback for a LibVLC instance.
|
||||||
|
This function is thread-safe: it will wait for any pending callbacks
|
||||||
|
invocation to complete.
|
||||||
@param cb: callback function pointer.
|
@param cb: callback function pointer.
|
||||||
@param data: opaque data pointer for the callback function @note Some log messages (especially debug) are emitted by LibVLC while initializing, before any LibVLC instance even exists. Thus this function does not require a LibVLC instance parameter. @warning As a consequence of not depending on a LibVLC instance, all logging callbacks are shared by all LibVLC instances within the process / address space. This also enables log messages to be emitted by LibVLC components that are not specific to any given LibVLC instance. @warning Do not call this function from within a logging callback. It would trigger a dead lock.
|
@param data: opaque data pointer for the callback function @note Some log messages (especially debug) are emitted by LibVLC while is being initialized. These messages cannot be captured with this interface. @warning A deadlock may occur if this function is called from the callback.
|
||||||
|
@param p_instance: libvlc instance.
|
||||||
@version: LibVLC 2.1.0 or later.
|
@version: LibVLC 2.1.0 or later.
|
||||||
'''
|
'''
|
||||||
f = _Cfunctions.get('libvlc_log_subscribe', None) or \
|
f = _Cfunctions.get('libvlc_log_set', None) or \
|
||||||
_Cfunction('libvlc_log_subscribe', ((1,), (1,), (1,),), None,
|
_Cfunction('libvlc_log_set', ((1,), (1,), (1,),), None,
|
||||||
None, ctypes.c_void_p, LogCb, ctypes.c_void_p)
|
None, Instance, LogCb, ctypes.c_void_p)
|
||||||
return f(sub, cb, data)
|
return f(cb, data, p_instance)
|
||||||
|
|
||||||
def libvlc_log_subscribe_file(sub, stream):
|
def libvlc_log_set_file(p_instance, stream):
|
||||||
'''Registers a logging callback to a file.
|
'''Sets up logging to a file.
|
||||||
@param stream: FILE pointer opened for writing (the FILE pointer must remain valid until L{libvlc_log_unsubscribe}()).
|
@param p_instance: libvlc instance.
|
||||||
|
@param stream: FILE pointer opened for writing (the FILE pointer must remain valid until L{libvlc_log_unset}()).
|
||||||
@version: LibVLC 2.1.0 or later.
|
@version: LibVLC 2.1.0 or later.
|
||||||
'''
|
'''
|
||||||
f = _Cfunctions.get('libvlc_log_subscribe_file', None) or \
|
f = _Cfunctions.get('libvlc_log_set_file', None) or \
|
||||||
_Cfunction('libvlc_log_subscribe_file', ((1,), (1,),), None,
|
_Cfunction('libvlc_log_set_file', ((1,), (1,),), None,
|
||||||
None, ctypes.c_void_p, FILE_ptr)
|
None, Instance, FILE_ptr)
|
||||||
return f(sub, stream)
|
return f(p_instance, stream)
|
||||||
|
|
||||||
def libvlc_log_unsubscribe(sub):
|
|
||||||
'''Deregisters a logging callback from LibVLC.
|
|
||||||
This function is thread-safe.
|
|
||||||
@note: After (and only after) L{libvlc_log_unsubscribe}() has returned,
|
|
||||||
LibVLC warrants that there are no more pending calls of the subscription
|
|
||||||
callback function.
|
|
||||||
@warning: Do not call this function from within a logging callback.
|
|
||||||
It would trigger a dead lock.
|
|
||||||
@param sub: initialized subscriber structure.
|
|
||||||
@version: LibVLC 2.1.0 or later.
|
|
||||||
'''
|
|
||||||
f = _Cfunctions.get('libvlc_log_unsubscribe', None) or \
|
|
||||||
_Cfunction('libvlc_log_unsubscribe', ((1,),), None,
|
|
||||||
None, ctypes.c_void_p)
|
|
||||||
return f(sub)
|
|
||||||
|
|
||||||
def libvlc_module_description_list_release(p_list):
|
def libvlc_module_description_list_release(p_list):
|
||||||
'''Release a list of module descriptions.
|
'''Release a list of module descriptions.
|
||||||
@ -3460,7 +3496,7 @@ def libvlc_media_new_as_node(p_instance, psz_name):
|
|||||||
ctypes.c_void_p, Instance, ctypes.c_char_p)
|
ctypes.c_void_p, Instance, ctypes.c_char_p)
|
||||||
return f(p_instance, psz_name)
|
return f(p_instance, psz_name)
|
||||||
|
|
||||||
def libvlc_media_add_option(p_md, ppsz_options):
|
def libvlc_media_add_option(p_md, psz_options):
|
||||||
'''Add an option to the media.
|
'''Add an option to the media.
|
||||||
This option will be used to determine how the media_player will
|
This option will be used to determine how the media_player will
|
||||||
read the media. This allows to use VLC's advanced
|
read the media. This allows to use VLC's advanced
|
||||||
@ -3473,14 +3509,14 @@ def libvlc_media_add_option(p_md, ppsz_options):
|
|||||||
such as text renderer options, have no effects on an individual media.
|
such as text renderer options, have no effects on an individual media.
|
||||||
These options must be set through L{libvlc_new}() instead.
|
These options must be set through L{libvlc_new}() instead.
|
||||||
@param p_md: the media descriptor.
|
@param p_md: the media descriptor.
|
||||||
@param ppsz_options: the options (as a string).
|
@param psz_options: the options (as a string).
|
||||||
'''
|
'''
|
||||||
f = _Cfunctions.get('libvlc_media_add_option', None) or \
|
f = _Cfunctions.get('libvlc_media_add_option', None) or \
|
||||||
_Cfunction('libvlc_media_add_option', ((1,), (1,),), None,
|
_Cfunction('libvlc_media_add_option', ((1,), (1,),), None,
|
||||||
None, Media, ctypes.c_char_p)
|
None, Media, ctypes.c_char_p)
|
||||||
return f(p_md, ppsz_options)
|
return f(p_md, psz_options)
|
||||||
|
|
||||||
def libvlc_media_add_option_flag(p_md, ppsz_options, i_flags):
|
def libvlc_media_add_option_flag(p_md, psz_options, i_flags):
|
||||||
'''Add an option to the media with configurable flags.
|
'''Add an option to the media with configurable flags.
|
||||||
This option will be used to determine how the media_player will
|
This option will be used to determine how the media_player will
|
||||||
read the media. This allows to use VLC's advanced
|
read the media. This allows to use VLC's advanced
|
||||||
@ -3491,13 +3527,13 @@ def libvlc_media_add_option_flag(p_md, ppsz_options, i_flags):
|
|||||||
such as text renderer options cannot be set on a single media. They
|
such as text renderer options cannot be set on a single media. They
|
||||||
must be set on the whole libvlc instance instead.
|
must be set on the whole libvlc instance instead.
|
||||||
@param p_md: the media descriptor.
|
@param p_md: the media descriptor.
|
||||||
@param ppsz_options: the options (as a string).
|
@param psz_options: the options (as a string).
|
||||||
@param i_flags: the flags for this option.
|
@param i_flags: the flags for this option.
|
||||||
'''
|
'''
|
||||||
f = _Cfunctions.get('libvlc_media_add_option_flag', None) or \
|
f = _Cfunctions.get('libvlc_media_add_option_flag', None) or \
|
||||||
_Cfunction('libvlc_media_add_option_flag', ((1,), (1,), (1,),), None,
|
_Cfunction('libvlc_media_add_option_flag', ((1,), (1,), (1,),), None,
|
||||||
None, Media, ctypes.c_char_p, ctypes.c_uint)
|
None, Media, ctypes.c_char_p, ctypes.c_uint)
|
||||||
return f(p_md, ppsz_options, i_flags)
|
return f(p_md, psz_options, i_flags)
|
||||||
|
|
||||||
def libvlc_media_retain(p_md):
|
def libvlc_media_retain(p_md):
|
||||||
'''Retain a reference to a media descriptor object (libvlc_media_t). Use
|
'''Retain a reference to a media descriptor object (libvlc_media_t). Use
|
||||||
@ -4949,12 +4985,12 @@ def libvlc_video_get_spu_description(p_mi):
|
|||||||
def libvlc_video_set_spu(p_mi, i_spu):
|
def libvlc_video_set_spu(p_mi, i_spu):
|
||||||
'''Set new video subtitle.
|
'''Set new video subtitle.
|
||||||
@param p_mi: the media player.
|
@param p_mi: the media player.
|
||||||
@param i_spu: new video subtitle to select.
|
@param i_spu: video subtitle track to select (i_id from track description).
|
||||||
@return: 0 on success, -1 if out of range.
|
@return: 0 on success, -1 if out of range.
|
||||||
'''
|
'''
|
||||||
f = _Cfunctions.get('libvlc_video_set_spu', None) or \
|
f = _Cfunctions.get('libvlc_video_set_spu', None) or \
|
||||||
_Cfunction('libvlc_video_set_spu', ((1,), (1,),), None,
|
_Cfunction('libvlc_video_set_spu', ((1,), (1,),), None,
|
||||||
ctypes.c_int, MediaPlayer, ctypes.c_uint)
|
ctypes.c_int, MediaPlayer, ctypes.c_int)
|
||||||
return f(p_mi, i_spu)
|
return f(p_mi, i_spu)
|
||||||
|
|
||||||
def libvlc_video_set_subtitle_file(p_mi, psz_subtitle):
|
def libvlc_video_set_subtitle_file(p_mi, psz_subtitle):
|
||||||
@ -5791,7 +5827,7 @@ def libvlc_vlm_get_event_manager(p_instance):
|
|||||||
# libvlc_printerr
|
# libvlc_printerr
|
||||||
# libvlc_set_exit_handler
|
# libvlc_set_exit_handler
|
||||||
|
|
||||||
# 18 function(s) not wrapped as methods:
|
# 15 function(s) not wrapped as methods:
|
||||||
# libvlc_audio_output_device_list_release
|
# libvlc_audio_output_device_list_release
|
||||||
# libvlc_audio_output_list_release
|
# libvlc_audio_output_list_release
|
||||||
# libvlc_clearerr
|
# libvlc_clearerr
|
||||||
@ -5802,9 +5838,6 @@ def libvlc_vlm_get_event_manager(p_instance):
|
|||||||
# libvlc_get_changeset
|
# libvlc_get_changeset
|
||||||
# libvlc_get_compiler
|
# libvlc_get_compiler
|
||||||
# libvlc_get_version
|
# libvlc_get_version
|
||||||
# libvlc_log_subscribe
|
|
||||||
# libvlc_log_subscribe_file
|
|
||||||
# libvlc_log_unsubscribe
|
|
||||||
# libvlc_media_tracks_release
|
# libvlc_media_tracks_release
|
||||||
# libvlc_module_description_list_release
|
# libvlc_module_description_list_release
|
||||||
# libvlc_new
|
# libvlc_new
|
||||||
|
@ -84,9 +84,8 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
def mouseMoveEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Drag and drop event does not care what data is selected
|
Drag and drop event does not care what data is selected as the recipient will use events to request the data
|
||||||
as the recipient will use events to request the data move
|
move just tell it what plugin to call
|
||||||
just tell it what plugin to call
|
|
||||||
"""
|
"""
|
||||||
if event.buttons() != QtCore.Qt.LeftButton:
|
if event.buttons() != QtCore.Qt.LeftButton:
|
||||||
event.ignore()
|
event.ignore()
|
||||||
@ -235,18 +234,22 @@ class ServiceManagerDialog(object):
|
|||||||
icon=u':/general/general_edit.png', triggers=self.create_custom)
|
icon=u':/general/general_edit.png', triggers=self.create_custom)
|
||||||
self.menu.addSeparator()
|
self.menu.addSeparator()
|
||||||
# Add AutoPlay menu actions
|
# Add AutoPlay menu actions
|
||||||
self.auto_play_slides_group = QtGui.QMenu(translate('OpenLP.ServiceManager', '&Auto play slides'))
|
self.auto_play_slides_menu = QtGui.QMenu(translate('OpenLP.ServiceManager', '&Auto play slides'))
|
||||||
self.menu.addMenu(self.auto_play_slides_group)
|
self.menu.addMenu(self.auto_play_slides_menu)
|
||||||
self.auto_play_slides_loop = create_widget_action(self.auto_play_slides_group,
|
auto_play_slides_group = QtGui.QActionGroup(self.auto_play_slides_menu)
|
||||||
|
auto_play_slides_group.setExclusive(True)
|
||||||
|
self.auto_play_slides_loop = create_widget_action(self.auto_play_slides_menu,
|
||||||
text=translate('OpenLP.ServiceManager', 'Auto play slides &Loop'),
|
text=translate('OpenLP.ServiceManager', 'Auto play slides &Loop'),
|
||||||
checked=False, triggers=self.toggle_auto_play_slides_loop)
|
checked=False, triggers=self.toggle_auto_play_slides_loop)
|
||||||
self.auto_play_slides_once = create_widget_action(self.auto_play_slides_group,
|
auto_play_slides_group.addAction(self.auto_play_slides_loop)
|
||||||
|
self.auto_play_slides_once = create_widget_action(self.auto_play_slides_menu,
|
||||||
text=translate('OpenLP.ServiceManager', 'Auto play slides &Once'),
|
text=translate('OpenLP.ServiceManager', 'Auto play slides &Once'),
|
||||||
checked=False, triggers=self.toggle_auto_play_slides_once)
|
checked=False, triggers=self.toggle_auto_play_slides_once)
|
||||||
self.auto_play_slides_group.addSeparator()
|
auto_play_slides_group.addAction(self.auto_play_slides_once)
|
||||||
self.timed_slide_interval = create_widget_action(self.auto_play_slides_group,
|
self.auto_play_slides_menu.addSeparator()
|
||||||
|
self.timed_slide_interval = create_widget_action(self.auto_play_slides_menu,
|
||||||
text=translate('OpenLP.ServiceManager', '&Delay between slides'),
|
text=translate('OpenLP.ServiceManager', '&Delay between slides'),
|
||||||
checked=False, triggers=self.on_timed_slide_interval)
|
triggers=self.on_timed_slide_interval)
|
||||||
self.menu.addSeparator()
|
self.menu.addSeparator()
|
||||||
self.preview_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'),
|
self.preview_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'),
|
||||||
icon=u':/general/general_preview.png', triggers=self.make_preview)
|
icon=u':/general/general_preview.png', triggers=self.make_preview)
|
||||||
@ -284,10 +287,9 @@ class ServiceManagerDialog(object):
|
|||||||
|
|
||||||
class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
"""
|
"""
|
||||||
Manages the services. This involves taking text strings from plugins and
|
Manages the services. This involves taking text strings from plugins and adding them to the service. This service
|
||||||
adding them to the service. This service can then be zipped up with all
|
can then be zipped up with all the resources used into one OSZ or oszl file for use on any OpenLP v2 installation.
|
||||||
the resources used into one OSZ or oszl file for use on any OpenLP v2
|
Also handles the UI tasks of moving things up and down etc.
|
||||||
installation. Also handles the UI tasks of moving things up and down etc.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
"""
|
"""
|
||||||
@ -316,8 +318,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def set_modified(self, modified=True):
|
def set_modified(self, modified=True):
|
||||||
"""
|
"""
|
||||||
Setter for property "modified". Sets whether or not the current service
|
Setter for property "modified". Sets whether or not the current service has been modified.
|
||||||
has been modified.
|
|
||||||
"""
|
"""
|
||||||
if modified:
|
if modified:
|
||||||
self.service_id += 1
|
self.service_id += 1
|
||||||
@ -361,7 +362,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def supported_suffixes(self, suffix):
|
def supported_suffixes(self, suffix):
|
||||||
"""
|
"""
|
||||||
Adds Suffixes supported to the master list. Called from Plugins.
|
Adds Suffixes supported to the master list. Called from Plugins.
|
||||||
|
|
||||||
``suffix``
|
``suffix``
|
||||||
New Suffix to be supported
|
New Suffix to be supported
|
||||||
@ -384,12 +385,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def on_load_service_clicked(self, load_file=None):
|
def on_load_service_clicked(self, load_file=None):
|
||||||
"""
|
"""
|
||||||
Loads the service file and saves the existing one it there is one
|
Loads the service file and saves the existing one it there is one unchanged.
|
||||||
unchanged
|
|
||||||
|
|
||||||
``load_file``
|
``load_file``
|
||||||
The service file to the loaded. Will be None is from menu so
|
The service file to the loaded. Will be None is from menu so selection will be required.
|
||||||
selection will be required.
|
|
||||||
"""
|
"""
|
||||||
if self.is_modified():
|
if self.is_modified():
|
||||||
result = self.save_modified_service()
|
result = self.save_modified_service()
|
||||||
@ -445,10 +444,9 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Save the current service file.
|
Save the current service file.
|
||||||
|
|
||||||
A temporary file is created so that we don't overwrite the existing one
|
A temporary file is created so that we don't overwrite the existing one and leave a mangled service file should
|
||||||
and leave a mangled service file should there be an error when saving.
|
there be an error when saving. Audio files are also copied into the service manager directory, and then packaged
|
||||||
Audio files are also copied into the service manager directory, and
|
into the zip file.
|
||||||
then packaged into the zip file.
|
|
||||||
"""
|
"""
|
||||||
if not self.file_name():
|
if not self.file_name():
|
||||||
return self.save_file_as()
|
return self.save_file_as()
|
||||||
@ -514,8 +512,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
total_size += file_size
|
total_size += file_size
|
||||||
log.debug(u'ServiceManager.save_file - ZIP contents size is %i bytes' % total_size)
|
log.debug(u'ServiceManager.save_file - ZIP contents size is %i bytes' % total_size)
|
||||||
service_content = cPickle.dumps(service)
|
service_content = cPickle.dumps(service)
|
||||||
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be
|
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX.
|
||||||
# extracted using unzip in UNIX.
|
|
||||||
allow_zip_64 = (total_size > 2147483648 + len(service_content))
|
allow_zip_64 = (total_size > 2147483648 + len(service_content))
|
||||||
log.debug(u'ServiceManager.save_file - allowZip64 is %s' % allow_zip_64)
|
log.debug(u'ServiceManager.save_file - allowZip64 is %s' % allow_zip_64)
|
||||||
zip_file = None
|
zip_file = None
|
||||||
@ -523,18 +520,15 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
try:
|
try:
|
||||||
zip_file = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED, allow_zip_64)
|
zip_file = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED, allow_zip_64)
|
||||||
# First we add service contents.
|
# First we add service contents. We save ALL file_names into ZIP using UTF-8.
|
||||||
# We save ALL file_names into ZIP using UTF-8.
|
|
||||||
zip_file.writestr(service_file_name.encode(u'utf-8'), service_content)
|
zip_file.writestr(service_file_name.encode(u'utf-8'), service_content)
|
||||||
# Finally add all the listed media files.
|
# Finally add all the listed media files.
|
||||||
for write_from in write_list:
|
for write_from in write_list:
|
||||||
zip_file.write(write_from, write_from.encode(u'utf-8'))
|
zip_file.write(write_from, write_from.encode(u'utf-8'))
|
||||||
for audio_from, audio_to in audio_files:
|
for audio_from, audio_to in audio_files:
|
||||||
if audio_from.startswith(u'audio'):
|
if audio_from.startswith(u'audio'):
|
||||||
# When items are saved, they get new unique_identifier. Let's copy the
|
# When items are saved, they get new unique_identifier. Let's copy the file to the new location.
|
||||||
# file to the new location. Unused files can be ignored,
|
# Unused files can be ignored, OpenLP automatically cleans up the service manager dir on exit.
|
||||||
# OpenLP automatically cleans up the service manager dir on
|
|
||||||
# exit.
|
|
||||||
audio_from = os.path.join(self.servicePath, audio_from)
|
audio_from = os.path.join(self.servicePath, audio_from)
|
||||||
save_file = os.path.join(self.servicePath, audio_to)
|
save_file = os.path.join(self.servicePath, audio_to)
|
||||||
save_path = os.path.split(save_file)[0]
|
save_path = os.path.split(save_file)[0]
|
||||||
@ -587,7 +581,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
for item in self.service_items:
|
for item in self.service_items:
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
service_item = item[u'service_item'].get_service_repr(self._save_lite)
|
service_item = item[u'service_item'].get_service_repr(self._save_lite)
|
||||||
#@todo check for file item on save.
|
#TODO: check for file item on save.
|
||||||
service.append({u'serviceitem': service_item})
|
service.append({u'serviceitem': service_item})
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
service_content = cPickle.dumps(service)
|
service_content = cPickle.dumps(service)
|
||||||
@ -622,8 +616,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def save_file_as(self):
|
def save_file_as(self):
|
||||||
"""
|
"""
|
||||||
Get a file name and then call :func:`ServiceManager.save_file` to
|
Get a file name and then call :func:`ServiceManager.save_file` to save the file.
|
||||||
save the file.
|
|
||||||
"""
|
"""
|
||||||
default_service_enabled = Settings().value(u'advanced/default service enabled')
|
default_service_enabled = Settings().value(u'advanced/default service enabled')
|
||||||
if default_service_enabled:
|
if default_service_enabled:
|
||||||
@ -645,8 +638,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
default_file_name = u''
|
default_file_name = u''
|
||||||
directory = Settings().value(self.main_window.service_manager_settings_section + u'/last directory')
|
directory = Settings().value(self.main_window.service_manager_settings_section + u'/last directory')
|
||||||
path = os.path.join(directory, default_file_name)
|
path = os.path.join(directory, default_file_name)
|
||||||
# SaveAs from osz to oszl is not valid as the files will be deleted
|
# SaveAs from osz to oszl is not valid as the files will be deleted on exit which is not sensible or usable in
|
||||||
# on exit which is not sensible or usable in the long term.
|
# the long term.
|
||||||
if self._file_name.endswith(u'oszl') or self.service_has_all_original_files:
|
if self._file_name.endswith(u'oszl') or self.service_has_all_original_files:
|
||||||
file_name = QtGui.QFileDialog.getSaveFileName(self.main_window, UiStrings().SaveService, path,
|
file_name = QtGui.QFileDialog.getSaveFileName(self.main_window, UiStrings().SaveService, path,
|
||||||
translate('OpenLP.ServiceManager',
|
translate('OpenLP.ServiceManager',
|
||||||
@ -764,9 +757,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def load_Last_file(self):
|
def load_Last_file(self):
|
||||||
"""
|
"""
|
||||||
Load the last service item from the service manager when the
|
Load the last service item from the service manager when the service was last closed. Can be blank if there was
|
||||||
service was last closed. Can be blank if there was no service
|
no service present.
|
||||||
present.
|
|
||||||
"""
|
"""
|
||||||
file_name = Settings().value(u'servicemanager/last file')
|
file_name = Settings().value(u'servicemanager/last file')
|
||||||
if file_name:
|
if file_name:
|
||||||
@ -798,7 +790,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.notes_action.setVisible(True)
|
self.notes_action.setVisible(True)
|
||||||
if service_item[u'service_item'].is_capable(ItemCapabilities.CanLoop) and \
|
if service_item[u'service_item'].is_capable(ItemCapabilities.CanLoop) and \
|
||||||
len(service_item[u'service_item'].get_frames()) > 1:
|
len(service_item[u'service_item'].get_frames()) > 1:
|
||||||
self.auto_play_slides_group.menuAction().setVisible(True)
|
self.auto_play_slides_menu.menuAction().setVisible(True)
|
||||||
self.auto_play_slides_once.setChecked(service_item[u'service_item'].auto_play_slides_once)
|
self.auto_play_slides_once.setChecked(service_item[u'service_item'].auto_play_slides_once)
|
||||||
self.auto_play_slides_loop.setChecked(service_item[u'service_item'].auto_play_slides_loop)
|
self.auto_play_slides_loop.setChecked(service_item[u'service_item'].auto_play_slides_loop)
|
||||||
self.timed_slide_interval.setChecked(service_item[u'service_item'].timed_slide_interval > 0)
|
self.timed_slide_interval.setChecked(service_item[u'service_item'].timed_slide_interval > 0)
|
||||||
@ -810,7 +802,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
translate('OpenLP.ServiceManager', '&Delay between slides') + delay_suffix)
|
translate('OpenLP.ServiceManager', '&Delay between slides') + delay_suffix)
|
||||||
# TODO for future: make group explains itself more visually
|
# TODO for future: make group explains itself more visually
|
||||||
else:
|
else:
|
||||||
self.auto_play_slides_group.menuAction().setVisible(False)
|
self.auto_play_slides_menu.menuAction().setVisible(False)
|
||||||
if service_item[u'service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
|
if service_item[u'service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
|
||||||
self.time_action.setVisible(True)
|
self.time_action.setVisible(True)
|
||||||
if service_item[u'service_item'].is_capable(ItemCapabilities.CanAutoStartForLive):
|
if service_item[u'service_item'].is_capable(ItemCapabilities.CanAutoStartForLive):
|
||||||
@ -860,8 +852,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def toggle_auto_play_slides_once(self):
|
def toggle_auto_play_slides_once(self):
|
||||||
"""
|
"""
|
||||||
Toggle Auto play slide once.
|
Toggle Auto play slide once. Inverts auto play once option for the item
|
||||||
Inverts auto play once option for the item
|
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
service_item = self.service_items[item][u'service_item']
|
service_item = self.service_items[item][u'service_item']
|
||||||
@ -922,8 +913,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def on_service_item_edit_form(self):
|
def on_service_item_edit_form(self):
|
||||||
"""
|
"""
|
||||||
Opens a dialog to edit the service item and update the service
|
Opens a dialog to edit the service item and update the service display if changes are saved.
|
||||||
display if changes are saved.
|
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
self.service_item_edit_form.set_service_item(self.service_items[item][u'service_item'])
|
self.service_item_edit_form.set_service_item(self.service_items[item][u'service_item'])
|
||||||
@ -933,17 +923,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def preview_live(self, unique_identifier, row):
|
def preview_live(self, unique_identifier, row):
|
||||||
"""
|
"""
|
||||||
Called by the SlideController to request a preview item be made live
|
Called by the SlideController to request a preview item be made live and allows the next preview to be updated
|
||||||
and allows the next preview to be updated if relevant.
|
if relevant.
|
||||||
|
|
||||||
|
|
||||||
``unique_identifier``
|
``unique_identifier``
|
||||||
Reference to the service_item
|
Reference to the service_item
|
||||||
|
|
||||||
|
|
||||||
``row``
|
``row``
|
||||||
individual row number
|
individual row number
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for sitem in self.service_items:
|
for sitem in self.service_items:
|
||||||
if sitem[u'service_item'].unique_identifier == unique_identifier:
|
if sitem[u'service_item'].unique_identifier == unique_identifier:
|
||||||
@ -1021,8 +1008,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def on_move_selection_up(self):
|
def on_move_selection_up(self):
|
||||||
"""
|
"""
|
||||||
Moves the cursor selection up the window.
|
Moves the cursor selection up the window. Called by the up arrow.
|
||||||
Called by the up arrow.
|
|
||||||
"""
|
"""
|
||||||
item = self.service_manager_list.currentItem()
|
item = self.service_manager_list.currentItem()
|
||||||
itemBefore = self.service_manager_list.itemAbove(item)
|
itemBefore = self.service_manager_list.itemAbove(item)
|
||||||
@ -1032,8 +1018,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def on_move_selection_down(self):
|
def on_move_selection_down(self):
|
||||||
"""
|
"""
|
||||||
Moves the cursor selection down the window.
|
Moves the cursor selection down the window. Called by the down arrow.
|
||||||
Called by the down arrow.
|
|
||||||
"""
|
"""
|
||||||
item = self.service_manager_list.currentItem()
|
item = self.service_manager_list.currentItem()
|
||||||
itemAfter = self.service_manager_list.itemBelow(item)
|
itemAfter = self.service_manager_list.itemBelow(item)
|
||||||
@ -1051,8 +1036,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def collapsed(self, item):
|
def collapsed(self, item):
|
||||||
"""
|
"""
|
||||||
Record if an item is collapsed. Used when repainting the list to get the
|
Record if an item is collapsed. Used when repainting the list to get the correct state.
|
||||||
correct state.
|
|
||||||
"""
|
"""
|
||||||
pos = item.data(0, QtCore.Qt.UserRole)
|
pos = item.data(0, QtCore.Qt.UserRole)
|
||||||
self.service_items[pos - 1][u'expanded'] = False
|
self.service_items[pos - 1][u'expanded'] = False
|
||||||
@ -1067,8 +1051,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def expanded(self, item):
|
def expanded(self, item):
|
||||||
"""
|
"""
|
||||||
Record if an item is collapsed. Used when repainting the list to get the
|
Record if an item is collapsed. Used when repainting the list to get the correct state.
|
||||||
correct state.
|
|
||||||
"""
|
"""
|
||||||
pos = item.data(0, QtCore.Qt.UserRole)
|
pos = item.data(0, QtCore.Qt.UserRole)
|
||||||
self.service_items[pos - 1][u'expanded'] = True
|
self.service_items[pos - 1][u'expanded'] = True
|
||||||
@ -1133,9 +1116,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def repaint_service_list(self, service_item, service_item_child):
|
def repaint_service_list(self, service_item, service_item_child):
|
||||||
"""
|
"""
|
||||||
Clear the existing service list and prepaint all the items. This is
|
Clear the existing service list and prepaint all the items. This is used when moving items as the move takes
|
||||||
used when moving items as the move takes place in a supporting list,
|
place in a supporting list, and when regenerating all the items due to theme changes.
|
||||||
and when regenerating all the items due to theme changes.
|
|
||||||
|
|
||||||
``service_item``
|
``service_item``
|
||||||
The item which changed. (int)
|
The item which changed. (int)
|
||||||
@ -1233,8 +1215,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def theme_change(self):
|
def theme_change(self):
|
||||||
"""
|
"""
|
||||||
The theme may have changed in the settings dialog so make
|
The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state.
|
||||||
sure the theme combo box is in the correct state.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'theme_change')
|
log.debug(u'theme_change')
|
||||||
visible = self.renderer.theme_level == ThemeLevel.Global
|
visible = self.renderer.theme_level == ThemeLevel.Global
|
||||||
@ -1243,8 +1224,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def regenerate_service_Items(self, changed=False):
|
def regenerate_service_Items(self, changed=False):
|
||||||
"""
|
"""
|
||||||
Rebuild the service list as things have changed and a
|
Rebuild the service list as things have changed and a repaint is the easiest way to do this.
|
||||||
repaint is the easiest way to do this.
|
|
||||||
"""
|
"""
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
log.debug(u'regenerate_service_Items')
|
log.debug(u'regenerate_service_Items')
|
||||||
@ -1272,8 +1252,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
for item in tempServiceItems:
|
for item in tempServiceItems:
|
||||||
self.add_service_item(item[u'service_item'], False, expand=item[u'expanded'], repaint=False,
|
self.add_service_item(item[u'service_item'], False, expand=item[u'expanded'], repaint=False,
|
||||||
selected=item[u'selected'])
|
selected=item[u'selected'])
|
||||||
# Set to False as items may have changed rendering
|
# Set to False as items may have changed rendering does not impact the saved song so True may also be valid
|
||||||
# does not impact the saved song so True may also be valid
|
|
||||||
if changed:
|
if changed:
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
# Repaint it once only at the end
|
# Repaint it once only at the end
|
||||||
@ -1282,8 +1261,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def service_item_update(self, edit_id, unique_identifier, temporary=False):
|
def service_item_update(self, edit_id, unique_identifier, temporary=False):
|
||||||
"""
|
"""
|
||||||
Triggered from plugins to update service items.
|
Triggered from plugins to update service items. Save the values as they will be used as part of the service load
|
||||||
Save the values as they will be used as part of the service load
|
|
||||||
"""
|
"""
|
||||||
self.load_item_unique_identifier = unique_identifier
|
self.load_item_unique_identifier = unique_identifier
|
||||||
self.load_item_edit_id = int(edit_id)
|
self.load_item_edit_id = int(edit_id)
|
||||||
@ -1291,8 +1269,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def replace_service_item(self, newItem):
|
def replace_service_item(self, newItem):
|
||||||
"""
|
"""
|
||||||
Using the service item passed replace the one with the same edit id
|
Using the service item passed replace the one with the same edit id if found.
|
||||||
if found.
|
|
||||||
"""
|
"""
|
||||||
for item_count, item in enumerate(self.service_items):
|
for item_count, item in enumerate(self.service_items):
|
||||||
if item[u'service_item'].edit_id == newItem.edit_id and item[u'service_item'].name == newItem.name:
|
if item[u'service_item'].edit_id == newItem.edit_id and item[u'service_item'].name == newItem.name:
|
||||||
@ -1375,8 +1352,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def on_make_live(self):
|
def on_make_live(self):
|
||||||
"""
|
"""
|
||||||
Send the current item to the Live slide controller but triggered
|
Send the current item to the Live slide controller but triggered by a tablewidget click event.
|
||||||
by a tablewidget click event.
|
|
||||||
"""
|
"""
|
||||||
self.make_live()
|
self.make_live()
|
||||||
|
|
||||||
@ -1385,8 +1361,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
Send the current item to the Live slide controller
|
Send the current item to the Live slide controller
|
||||||
|
|
||||||
``row``
|
``row``
|
||||||
Row number to be displayed if from preview.
|
Row number to be displayed if from preview. -1 is passed if the value is not set
|
||||||
-1 is passed if the value is not set
|
|
||||||
"""
|
"""
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
# No items in service
|
# No items in service
|
||||||
@ -1404,7 +1379,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.preview_controller.addServiceManagerItem(self.service_items[item][u'service_item'], 0)
|
self.preview_controller.addServiceManagerItem(self.service_items[item][u'service_item'], 0)
|
||||||
next_item = self.service_manager_list.topLevelItem(item)
|
next_item = self.service_manager_list.topLevelItem(item)
|
||||||
self.service_manager_list.setCurrentItem(next_item)
|
self.service_manager_list.setCurrentItem(next_item)
|
||||||
self.live_controller.previewListWidget.setFocus()
|
self.live_controller.preview_list_widget.setFocus()
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
||||||
translate('OpenLP.ServiceManager',
|
translate('OpenLP.ServiceManager',
|
||||||
@ -1431,10 +1406,9 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def find_service_item(self):
|
def find_service_item(self):
|
||||||
"""
|
"""
|
||||||
Finds the first selected ServiceItem in the list and returns the
|
Finds the first selected ServiceItem in the list and returns the position of the serviceitem and its selected
|
||||||
position of the serviceitem and its selected child item. For example,
|
child item. For example, if the third child item (in the Slidecontroller known as slide) in the second service
|
||||||
if the third child item (in the Slidecontroller known as slide) in the
|
item is selected this will return::
|
||||||
second service item is selected this will return::
|
|
||||||
|
|
||||||
(1, 2)
|
(1, 2)
|
||||||
"""
|
"""
|
||||||
@ -1456,8 +1430,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
|
|
||||||
def drop_event(self, event):
|
def drop_event(self, event):
|
||||||
"""
|
"""
|
||||||
Receive drop event and trigger an internal event to get the
|
Receive drop event and trigger an internal event to get the plugins to build and push the correct service item.
|
||||||
plugins to build and push the correct service item
|
|
||||||
The drag event payload carries the plugin name
|
The drag event payload carries the plugin name
|
||||||
|
|
||||||
``event``
|
``event``
|
||||||
@ -1529,8 +1502,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
theme_group = QtGui.QActionGroup(self.theme_menu)
|
theme_group = QtGui.QActionGroup(self.theme_menu)
|
||||||
theme_group.setExclusive(True)
|
theme_group.setExclusive(True)
|
||||||
theme_group.setObjectName(u'theme_group')
|
theme_group.setObjectName(u'theme_group')
|
||||||
# Create a "Default" theme, which allows the user to reset the item's
|
# Create a "Default" theme, which allows the user to reset the item's theme to the service theme or global
|
||||||
# theme to the service theme or global theme.
|
# theme.
|
||||||
defaultTheme = create_widget_action(self.theme_menu, text=UiStrings().Default, checked=False,
|
defaultTheme = create_widget_action(self.theme_menu, text=UiStrings().Default, checked=False,
|
||||||
triggers=self.on_theme_change_action)
|
triggers=self.on_theme_change_action)
|
||||||
self.theme_menu.setDefaultAction(defaultTheme)
|
self.theme_menu.setDefaultAction(defaultTheme)
|
||||||
|
@ -44,6 +44,8 @@ from openlp.core.utils.actions import ActionList, CategoryOrder
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Threshold which has to be trespassed to toggle.
|
||||||
|
HIDE_MENU_THRESHOLD = 27
|
||||||
AUDIO_TIME_LABEL_STYLESHEET = u'background-color: palette(background); ' \
|
AUDIO_TIME_LABEL_STYLESHEET = u'background-color: palette(background); ' \
|
||||||
u'border-top-color: palette(shadow); ' \
|
u'border-top-color: palette(shadow); ' \
|
||||||
u'border-left-color: palette(shadow); ' \
|
u'border-left-color: palette(shadow); ' \
|
||||||
@ -588,12 +590,12 @@ class SlideController(DisplayController):
|
|||||||
if self.is_live:
|
if self.is_live:
|
||||||
# Space used by the toolbar.
|
# Space used by the toolbar.
|
||||||
used_space = self.toolbar.size().width() + self.hide_menu.size().width()
|
used_space = self.toolbar.size().width() + self.hide_menu.size().width()
|
||||||
# The + 40 is needed to prevent flickering. This can be considered a "buffer".
|
# Add the threshold to prevent flickering.
|
||||||
if width > used_space + 40 and self.hide_menu.isVisible():
|
if width > used_space + HIDE_MENU_THRESHOLD and self.hide_menu.isVisible():
|
||||||
self.toolbar.set_widget_visible(self.narrow_menu, False)
|
self.toolbar.set_widget_visible(self.narrow_menu, False)
|
||||||
self.toolbar.set_widget_visible(self.wide_menu)
|
self.toolbar.set_widget_visible(self.wide_menu)
|
||||||
# The - 40 is needed to prevent flickering. This can be considered a "buffer".
|
# Take away a threshold to prevent flickering.
|
||||||
elif width < used_space - 40 and not self.hide_menu.isVisible():
|
elif width < used_space - HIDE_MENU_THRESHOLD and not self.hide_menu.isVisible():
|
||||||
self.toolbar.set_widget_visible(self.wide_menu, False)
|
self.toolbar.set_widget_visible(self.wide_menu, False)
|
||||||
self.toolbar.set_widget_visible(self.narrow_menu)
|
self.toolbar.set_widget_visible(self.narrow_menu)
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, Backgr
|
|||||||
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
||||||
from openlp.core.theme import Theme
|
from openlp.core.theme import Theme
|
||||||
from openlp.core.ui import FileRenameForm, ThemeForm
|
from openlp.core.ui import FileRenameForm, ThemeForm
|
||||||
from openlp.core.utils import AppLocation, delete_file, locale_compare, get_filesystem_encoding
|
from openlp.core.utils import AppLocation, delete_file, get_locale_key, get_filesystem_encoding
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -418,7 +418,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
self.theme_list_widget.clear()
|
self.theme_list_widget.clear()
|
||||||
files = AppLocation.get_files(self.settings_section, u'.png')
|
files = AppLocation.get_files(self.settings_section, u'.png')
|
||||||
# Sort the themes by its name considering language specific
|
# Sort the themes by its name considering language specific
|
||||||
files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare)
|
files.sort(key=lambda file_name: get_locale_key(unicode(file_name)))
|
||||||
# now process the file list of png files
|
# now process the file list of png files
|
||||||
for name in files:
|
for name in files:
|
||||||
# check to see file is in theme root directory
|
# check to see file is in theme root directory
|
||||||
|
@ -38,6 +38,7 @@ import re
|
|||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
import sys
|
import sys
|
||||||
import urllib2
|
import urllib2
|
||||||
|
import icu
|
||||||
|
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
|
|
||||||
@ -56,10 +57,12 @@ from openlp.core.lib import translate
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
APPLICATION_VERSION = {}
|
APPLICATION_VERSION = {}
|
||||||
IMAGES_FILTER = None
|
IMAGES_FILTER = None
|
||||||
|
ICU_COLLATOR = None
|
||||||
UNO_CONNECTION_TYPE = u'pipe'
|
UNO_CONNECTION_TYPE = u'pipe'
|
||||||
#UNO_CONNECTION_TYPE = u'socket'
|
#UNO_CONNECTION_TYPE = u'socket'
|
||||||
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
|
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
|
||||||
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
|
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
|
||||||
|
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
|
||||||
|
|
||||||
|
|
||||||
class VersionThread(QtCore.QThread):
|
class VersionThread(QtCore.QThread):
|
||||||
@ -379,21 +382,32 @@ def format_time(text, local_time):
|
|||||||
return re.sub('\%[a-zA-Z]', match_formatting, text)
|
return re.sub('\%[a-zA-Z]', match_formatting, text)
|
||||||
|
|
||||||
|
|
||||||
def locale_compare(string1, string2):
|
def get_locale_key(string):
|
||||||
"""
|
"""
|
||||||
Compares two strings according to the current locale settings.
|
Creates a key for case insensitive, locale aware string sorting.
|
||||||
|
|
||||||
As any other compare function, returns a negative, or a positive value,
|
|
||||||
or 0, depending on whether string1 collates before or after string2 or
|
|
||||||
is equal to it. Comparison is case insensitive.
|
|
||||||
"""
|
"""
|
||||||
# Function locale.strcoll() from standard Python library does not work properly on Windows.
|
string = string.lower()
|
||||||
return locale.strcoll(string1.lower(), string2.lower())
|
# For Python 3 on platforms other than Windows ICU is not necessary. In those cases locale.strxfrm(str) can be used.
|
||||||
|
global ICU_COLLATOR
|
||||||
|
if ICU_COLLATOR is None:
|
||||||
|
from languagemanager import LanguageManager
|
||||||
|
locale = LanguageManager.get_language()
|
||||||
|
icu_locale = icu.Locale(locale)
|
||||||
|
ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
|
||||||
|
return ICU_COLLATOR.getSortKey(string)
|
||||||
|
|
||||||
|
|
||||||
# For performance reasons provide direct reference to compare function without wrapping it in another function making
|
def get_natural_key(string):
|
||||||
# the string lowercase. This is needed for sorting songs.
|
"""
|
||||||
locale_direct_compare = locale.strcoll
|
Generate a key for locale aware natural string sorting.
|
||||||
|
Returns a list of string compare keys and integers.
|
||||||
|
"""
|
||||||
|
key = DIGITS_OR_NONDIGITS.findall(string)
|
||||||
|
key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
|
||||||
|
# Python 3 does not support comparision of different types anymore. So make sure, that we do not compare str and int.
|
||||||
|
#if string[0].isdigit():
|
||||||
|
# return [''] + key
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
from applocation import AppLocation
|
from applocation import AppLocation
|
||||||
@ -403,4 +417,4 @@ from actions import ActionList
|
|||||||
|
|
||||||
__all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version',
|
__all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version',
|
||||||
u'add_actions', u'get_filesystem_encoding', u'get_web_page', u'get_uno_command', u'get_uno_instance',
|
u'add_actions', u'get_filesystem_encoding', u'get_web_page', u'get_uno_command', u'get_uno_instance',
|
||||||
u'delete_file', u'clean_filename', u'format_time', u'locale_compare', u'locale_direct_compare']
|
u'delete_file', u'clean_filename', u'format_time', u'get_locale_key', u'get_natural_key']
|
||||||
|
@ -38,7 +38,7 @@ from openlp.core.lib import Settings, UiStrings, translate
|
|||||||
from openlp.core.lib.db import delete_database
|
from openlp.core.lib.db import delete_database
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
||||||
from openlp.core.utils import AppLocation, locale_compare
|
from openlp.core.utils import AppLocation, get_locale_key
|
||||||
from openlp.plugins.bibles.lib.manager import BibleFormat
|
from openlp.plugins.bibles.lib.manager import BibleFormat
|
||||||
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
|
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
|
||||||
|
|
||||||
@ -455,7 +455,7 @@ class BibleImportForm(OpenLPWizard):
|
|||||||
"""
|
"""
|
||||||
self.webTranslationComboBox.clear()
|
self.webTranslationComboBox.clear()
|
||||||
bibles = self.web_bible_list[index].keys()
|
bibles = self.web_bible_list[index].keys()
|
||||||
bibles.sort(cmp=locale_compare)
|
bibles.sort(key=get_locale_key)
|
||||||
self.webTranslationComboBox.addItems(bibles)
|
self.webTranslationComboBox.addItems(bibles)
|
||||||
|
|
||||||
def onOsisBrowseButtonClicked(self):
|
def onOsisBrowseButtonClicked(self):
|
||||||
|
@ -36,7 +36,7 @@ from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, Servic
|
|||||||
from openlp.core.lib.searchedit import SearchEdit
|
from openlp.core.lib.searchedit import SearchEdit
|
||||||
from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
|
from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
|
||||||
critical_error_message_box, find_and_set_in_combo_box, build_icon
|
critical_error_message_box, find_and_set_in_combo_box, build_icon
|
||||||
from openlp.core.utils import locale_compare
|
from openlp.core.utils import get_locale_key
|
||||||
from openlp.plugins.bibles.forms import BibleImportForm, EditBibleForm
|
from openlp.plugins.bibles.forms import BibleImportForm, EditBibleForm
|
||||||
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \
|
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \
|
||||||
LanguageSelection, BibleStrings
|
LanguageSelection, BibleStrings
|
||||||
@ -325,7 +325,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
# Get all bibles and sort the list.
|
# Get all bibles and sort the list.
|
||||||
bibles = self.plugin.manager.get_bibles().keys()
|
bibles = self.plugin.manager.get_bibles().keys()
|
||||||
bibles = filter(None, bibles)
|
bibles = filter(None, bibles)
|
||||||
bibles.sort(cmp=locale_compare)
|
bibles.sort(key=get_locale_key)
|
||||||
# Load the bibles into the combo boxes.
|
# Load the bibles into the combo boxes.
|
||||||
self.quickVersionComboBox.addItems(bibles)
|
self.quickVersionComboBox.addItems(bibles)
|
||||||
self.quickSecondComboBox.addItems(bibles)
|
self.quickSecondComboBox.addItems(bibles)
|
||||||
@ -461,7 +461,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
for book in book_data:
|
for book in book_data:
|
||||||
data = BiblesResourcesDB.get_book_by_id(book.book_reference_id)
|
data = BiblesResourcesDB.get_book_by_id(book.book_reference_id)
|
||||||
books.append(data[u'name'] + u' ')
|
books.append(data[u'name'] + u' ')
|
||||||
books.sort(cmp=locale_compare)
|
books.sort(key=get_locale_key)
|
||||||
set_case_insensitive_completer(books, self.quickSearchEdit)
|
set_case_insensitive_completer(books, self.quickSearchEdit)
|
||||||
|
|
||||||
def on_import_click(self):
|
def on_import_click(self):
|
||||||
|
@ -35,7 +35,7 @@ from sqlalchemy import Column, Table, types
|
|||||||
from sqlalchemy.orm import mapper
|
from sqlalchemy.orm import mapper
|
||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
from openlp.core.utils import locale_compare
|
from openlp.core.utils import get_locale_key
|
||||||
|
|
||||||
class CustomSlide(BaseModel):
|
class CustomSlide(BaseModel):
|
||||||
"""
|
"""
|
||||||
@ -44,11 +44,10 @@ class CustomSlide(BaseModel):
|
|||||||
# By default sort the customs by its title considering language specific
|
# By default sort the customs by its title considering language specific
|
||||||
# characters.
|
# characters.
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
r = locale_compare(self.title, other.title)
|
return get_locale_key(self.title) < get_locale_key(other.title)
|
||||||
return True if r < 0 else False
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return 0 == locale_compare(self.title, other.title)
|
return get_locale_key(self.title) == get_locale_key(other.title)
|
||||||
|
|
||||||
|
|
||||||
def init_schema(url):
|
def init_schema(url):
|
||||||
|
@ -36,7 +36,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem, Registry, Servic
|
|||||||
StringContent, TreeWidgetWithDnD, UiStrings, build_icon, check_directory_exists, check_item_selected, \
|
StringContent, TreeWidgetWithDnD, UiStrings, build_icon, check_directory_exists, check_item_selected, \
|
||||||
create_thumb, translate, validate_thumb
|
create_thumb, translate, validate_thumb
|
||||||
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
|
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
|
||||||
from openlp.core.utils import AppLocation, delete_file, locale_compare, get_images_filter
|
from openlp.core.utils import AppLocation, delete_file, get_locale_key, get_images_filter
|
||||||
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
|
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
|
||||||
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
|
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
The ID of the group that will be added recursively
|
The ID of the group that will be added recursively
|
||||||
"""
|
"""
|
||||||
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
|
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
|
||||||
image_groups.sort(cmp=locale_compare, key=lambda group_object: group_object.group_name)
|
image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name))
|
||||||
folder_icon = build_icon(u':/images/image_group.png')
|
folder_icon = build_icon(u':/images/image_group.png')
|
||||||
for image_group in image_groups:
|
for image_group in image_groups:
|
||||||
group = QtGui.QTreeWidgetItem()
|
group = QtGui.QTreeWidgetItem()
|
||||||
@ -286,7 +286,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
combobox.clear()
|
combobox.clear()
|
||||||
combobox.top_level_group_added = False
|
combobox.top_level_group_added = False
|
||||||
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
|
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
|
||||||
image_groups.sort(cmp=locale_compare, key=lambda group_object: group_object.group_name)
|
image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name))
|
||||||
for image_group in image_groups:
|
for image_group in image_groups:
|
||||||
combobox.addItem(prefix + image_group.group_name, image_group.id)
|
combobox.addItem(prefix + image_group.group_name, image_group.id)
|
||||||
self.fill_groups_combobox(combobox, image_group.id, prefix + ' ')
|
self.fill_groups_combobox(combobox, image_group.id, prefix + ' ')
|
||||||
@ -338,7 +338,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
self.expand_group(open_group.id)
|
self.expand_group(open_group.id)
|
||||||
# Sort the images by its filename considering language specific
|
# Sort the images by its filename considering language specific
|
||||||
# characters.
|
# characters.
|
||||||
images.sort(cmp=locale_compare, key=lambda image_object: os.path.split(unicode(image_object.filename))[1])
|
images.sort(key=lambda image_object: get_locale_key(os.path.split(unicode(image_object.filename))[1]))
|
||||||
for imageFile in images:
|
for imageFile in images:
|
||||||
log.debug(u'Loading image: %s', imageFile.filename)
|
log.debug(u'Loading image: %s', imageFile.filename)
|
||||||
filename = os.path.split(imageFile.filename)[1]
|
filename = os.path.split(imageFile.filename)[1]
|
||||||
@ -526,9 +526,9 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
group_items.append(item)
|
group_items.append(item)
|
||||||
if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames):
|
if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames):
|
||||||
image_items.append(item)
|
image_items.append(item)
|
||||||
group_items.sort(cmp=locale_compare, key=lambda item: item.text(0))
|
group_items.sort(key=lambda item: get_locale_key(item.text(0)))
|
||||||
target_group.addChildren(group_items)
|
target_group.addChildren(group_items)
|
||||||
image_items.sort(cmp=locale_compare, key=lambda item: item.text(0))
|
image_items.sort(key=lambda item: get_locale_key(item.text(0)))
|
||||||
target_group.addChildren(image_items)
|
target_group.addChildren(image_items)
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
||||||
|
@ -37,7 +37,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, Regist
|
|||||||
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
||||||
from openlp.core.ui.media import get_media_players, set_media_players
|
from openlp.core.ui.media import get_media_players, set_media_players
|
||||||
from openlp.core.utils import AppLocation, locale_compare
|
from openlp.core.utils import AppLocation, get_locale_key
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
def load_list(self, media, target_group=None):
|
def load_list(self, media, target_group=None):
|
||||||
# Sort the media by its filename considering language specific
|
# Sort the media by its filename considering language specific
|
||||||
# characters.
|
# characters.
|
||||||
media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1])
|
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
||||||
for track in media:
|
for track in media:
|
||||||
track_info = QtCore.QFileInfo(track)
|
track_info = QtCore.QFileInfo(track)
|
||||||
if not os.path.exists(track):
|
if not os.path.exists(track):
|
||||||
@ -287,7 +287,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def getList(self, type=MediaType.Audio):
|
def getList(self, type=MediaType.Audio):
|
||||||
media = Settings().value(self.settings_section + u'/media files')
|
media = Settings().value(self.settings_section + u'/media files')
|
||||||
media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1])
|
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
||||||
ext = []
|
ext = []
|
||||||
if type == MediaType.Audio:
|
if type == MediaType.Audio:
|
||||||
ext = self.media_controller.audio_extensions_list
|
ext = self.media_controller.audio_extensions_list
|
||||||
|
@ -118,31 +118,6 @@ class MediaPlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
return self.media_controller.get_media_display_html()
|
return self.media_controller.get_media_display_html()
|
||||||
|
|
||||||
def app_startup(self):
|
|
||||||
"""
|
|
||||||
Do a couple of things when the app starts up. In this particular case
|
|
||||||
we want to check if we have the old "Use Phonon" setting, and convert
|
|
||||||
it to "enable Phonon" and "make it the first one in the list".
|
|
||||||
"""
|
|
||||||
Plugin.app_startup(self)
|
|
||||||
settings = Settings()
|
|
||||||
settings.beginGroup(self.settings_section)
|
|
||||||
if settings.contains(u'use phonon'):
|
|
||||||
log.info(u'Found old Phonon setting')
|
|
||||||
players = self.media_controller.mediaPlayers.keys()
|
|
||||||
has_phonon = u'phonon' in players
|
|
||||||
if settings.value(u'use phonon') and has_phonon:
|
|
||||||
log.debug(u'Converting old setting to new setting')
|
|
||||||
new_players = []
|
|
||||||
if players:
|
|
||||||
new_players = [player for player in players if player != u'phonon']
|
|
||||||
new_players.insert(0, u'phonon')
|
|
||||||
self.media_controller.mediaPlayers[u'phonon'].is_active = True
|
|
||||||
settings.setValue(u'players', u','.join(new_players))
|
|
||||||
self.settingsTab.load()
|
|
||||||
settings.remove(u'use phonon')
|
|
||||||
settings.endGroup()
|
|
||||||
|
|
||||||
def _get_media_controller(self):
|
def _get_media_controller(self):
|
||||||
"""
|
"""
|
||||||
Adds the media controller to the class dynamically
|
Adds the media controller to the class dynamically
|
||||||
|
@ -35,7 +35,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
from openlp.core.lib import MediaManagerItem, Registry, ItemCapabilities, ServiceItemContext, Settings, UiStrings, \
|
from openlp.core.lib import MediaManagerItem, Registry, ItemCapabilities, ServiceItemContext, Settings, UiStrings, \
|
||||||
build_icon, check_item_selected, create_thumb, translate, validate_thumb
|
build_icon, check_item_selected, create_thumb, translate, validate_thumb
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.utils import locale_compare
|
from openlp.core.utils import get_locale_key
|
||||||
from openlp.plugins.presentations.lib import MessageListener
|
from openlp.plugins.presentations.lib import MessageListener
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -153,8 +153,7 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
if not initialLoad:
|
if not initialLoad:
|
||||||
self.main_window.display_progress_bar(len(files))
|
self.main_window.display_progress_bar(len(files))
|
||||||
# Sort the presentations by its filename considering language specific characters.
|
# Sort the presentations by its filename considering language specific characters.
|
||||||
files.sort(cmp=locale_compare,
|
files.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
||||||
key=lambda filename: os.path.split(unicode(filename))[1])
|
|
||||||
for file in files:
|
for file in files:
|
||||||
if not initialLoad:
|
if not initialLoad:
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
|
@ -37,7 +37,6 @@ from PyQt4 import QtCore, QtGui
|
|||||||
from openlp.core.lib import Registry, UiStrings, create_separated_list, build_icon, translate
|
from openlp.core.lib import Registry, UiStrings, create_separated_list, build_icon, translate
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
||||||
from openlp.plugins.songs.lib import natcmp
|
|
||||||
from openlp.plugins.songs.lib.db import Song
|
from openlp.plugins.songs.lib.db import Song
|
||||||
from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
|
from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
|
||||||
|
|
||||||
@ -222,7 +221,7 @@ class SongExportForm(OpenLPWizard):
|
|||||||
# Load the list of songs.
|
# Load the list of songs.
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
songs = self.plugin.manager.get_all_objects(Song)
|
songs = self.plugin.manager.get_all_objects(Song)
|
||||||
songs.sort(cmp=natcmp, key=lambda song: song.sort_key)
|
songs.sort(key=lambda song: song.sort_key)
|
||||||
for song in songs:
|
for song in songs:
|
||||||
# No need to export temporary songs.
|
# No need to export temporary songs.
|
||||||
if song.temporary:
|
if song.temporary:
|
||||||
|
@ -34,7 +34,7 @@ import re
|
|||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate
|
||||||
from openlp.core.utils import CONTROL_CHARS, locale_direct_compare
|
from openlp.core.utils import CONTROL_CHARS
|
||||||
from db import Author
|
from db import Author
|
||||||
from ui import SongStrings
|
from ui import SongStrings
|
||||||
|
|
||||||
@ -168,6 +168,7 @@ class VerseType(object):
|
|||||||
translate('SongsPlugin.VerseType', 'Intro'),
|
translate('SongsPlugin.VerseType', 'Intro'),
|
||||||
translate('SongsPlugin.VerseType', 'Ending'),
|
translate('SongsPlugin.VerseType', 'Ending'),
|
||||||
translate('SongsPlugin.VerseType', 'Other')]
|
translate('SongsPlugin.VerseType', 'Other')]
|
||||||
|
|
||||||
translated_tags = [name[0].lower() for name in translated_names]
|
translated_tags = [name[0].lower() for name in translated_names]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -592,37 +593,3 @@ def strip_rtf(text, default_encoding=None):
|
|||||||
text = u''.join(out)
|
text = u''.join(out)
|
||||||
return text, default_encoding
|
return text, default_encoding
|
||||||
|
|
||||||
|
|
||||||
def natcmp(a, b):
|
|
||||||
"""
|
|
||||||
Natural string comparison which mimics the behaviour of Python's internal cmp function.
|
|
||||||
"""
|
|
||||||
if len(a) <= len(b):
|
|
||||||
for i, key in enumerate(a):
|
|
||||||
if isinstance(key, int) and isinstance(b[i], int):
|
|
||||||
result = cmp(key, b[i])
|
|
||||||
elif isinstance(key, int) and not isinstance(b[i], int):
|
|
||||||
result = locale_direct_compare(str(key), b[i])
|
|
||||||
elif not isinstance(key, int) and isinstance(b[i], int):
|
|
||||||
result = locale_direct_compare(key, str(b[i]))
|
|
||||||
else:
|
|
||||||
result = locale_direct_compare(key, b[i])
|
|
||||||
if result != 0:
|
|
||||||
return result
|
|
||||||
if len(a) == len(b):
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
return -1
|
|
||||||
else:
|
|
||||||
for i, key in enumerate(b):
|
|
||||||
if isinstance(a[i], int) and isinstance(key, int):
|
|
||||||
result = cmp(a[i], key)
|
|
||||||
elif isinstance(a[i], int) and not isinstance(key, int):
|
|
||||||
result = locale_direct_compare(str(a[i]), key)
|
|
||||||
elif not isinstance(a[i], int) and isinstance(key, int):
|
|
||||||
result = locale_direct_compare(a[i], str(key))
|
|
||||||
else:
|
|
||||||
result = locale_direct_compare(a[i], key)
|
|
||||||
if result != 0:
|
|
||||||
return result
|
|
||||||
return 1
|
|
||||||
|
@ -38,6 +38,7 @@ from sqlalchemy.orm import mapper, relation, reconstructor
|
|||||||
from sqlalchemy.sql.expression import func
|
from sqlalchemy.sql.expression import func
|
||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
|
from openlp.core.utils import get_natural_key
|
||||||
|
|
||||||
|
|
||||||
class Author(BaseModel):
|
class Author(BaseModel):
|
||||||
@ -69,36 +70,15 @@ class Song(BaseModel):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sort_key = ()
|
self.sort_key = ()
|
||||||
|
|
||||||
def _try_int(self, s):
|
|
||||||
"""
|
|
||||||
Convert to integer if possible.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return int(s)
|
|
||||||
except:
|
|
||||||
return s.lower()
|
|
||||||
|
|
||||||
def _natsort_key(self, s):
|
|
||||||
"""
|
|
||||||
Used internally to get a tuple by which s is sorted.
|
|
||||||
"""
|
|
||||||
return map(self._try_int, re.findall(r'(\d+|\D+)', s))
|
|
||||||
|
|
||||||
# This decorator tells sqlalchemy to call this method everytime
|
|
||||||
# any data on this object is updated.
|
|
||||||
|
|
||||||
@reconstructor
|
@reconstructor
|
||||||
def init_on_load(self):
|
def init_on_load(self):
|
||||||
"""
|
"""
|
||||||
Precompute a tuple to be used for sorting.
|
Precompute a natural sorting, locale aware sorting key.
|
||||||
|
|
||||||
Song sorting is performance sensitive operation.
|
Song sorting is performance sensitive operation.
|
||||||
To get maximum speed lets precompute the string
|
To get maximum speed lets precompute the sorting key.
|
||||||
used for comparison.
|
|
||||||
"""
|
"""
|
||||||
# Avoid the overhead of converting string to lowercase and to QString
|
self.sort_key = get_natural_key(self.title)
|
||||||
# with every call to sort().
|
|
||||||
self.sort_key = self._natsort_key(self.title)
|
|
||||||
|
|
||||||
|
|
||||||
class Topic(BaseModel):
|
class Topic(BaseModel):
|
||||||
|
@ -43,7 +43,7 @@ from openlp.plugins.songs.forms.editsongform import EditSongForm
|
|||||||
from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
|
from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
|
||||||
from openlp.plugins.songs.forms.songimportform import SongImportForm
|
from openlp.plugins.songs.forms.songimportform import SongImportForm
|
||||||
from openlp.plugins.songs.forms.songexportform import SongExportForm
|
from openlp.plugins.songs.forms.songexportform import SongExportForm
|
||||||
from openlp.plugins.songs.lib import VerseType, clean_string, natcmp
|
from openlp.plugins.songs.lib import VerseType, clean_string
|
||||||
from openlp.plugins.songs.lib.db import Author, Song, Book, MediaFile
|
from openlp.plugins.songs.lib.db import Author, Song, Book, MediaFile
|
||||||
from openlp.plugins.songs.lib.ui import SongStrings
|
from openlp.plugins.songs.lib.ui import SongStrings
|
||||||
from openlp.plugins.songs.lib.xml import OpenLyrics, SongXML
|
from openlp.plugins.songs.lib.xml import OpenLyrics, SongXML
|
||||||
@ -225,7 +225,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
log.debug(u'display results Song')
|
log.debug(u'display results Song')
|
||||||
self.save_auto_select_id()
|
self.save_auto_select_id()
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
searchresults.sort(cmp=natcmp, key=lambda song: song.sort_key)
|
searchresults.sort(key=lambda song: song.sort_key)
|
||||||
for song in searchresults:
|
for song in searchresults:
|
||||||
# Do not display temporary songs
|
# Do not display temporary songs
|
||||||
if song.temporary:
|
if song.temporary:
|
||||||
|
@ -260,7 +260,10 @@ class SongImport(QtCore.QObject):
|
|||||||
elif int(verse_def[1:]) > self.verseCounts[verse_def[0]]:
|
elif int(verse_def[1:]) > self.verseCounts[verse_def[0]]:
|
||||||
self.verseCounts[verse_def[0]] = int(verse_def[1:])
|
self.verseCounts[verse_def[0]] = int(verse_def[1:])
|
||||||
self.verses.append([verse_def, verse_text.rstrip(), lang])
|
self.verses.append([verse_def, verse_text.rstrip(), lang])
|
||||||
self.verseOrderListGenerated.append(verse_def)
|
# A verse_def refers to all verses with that name, adding it once adds every instance, so do not add if already
|
||||||
|
# used.
|
||||||
|
if verse_def not in self.verseOrderListGenerated:
|
||||||
|
self.verseOrderListGenerated.append(verse_def)
|
||||||
|
|
||||||
def repeatVerse(self):
|
def repeatVerse(self):
|
||||||
"""
|
"""
|
||||||
|
@ -32,6 +32,7 @@ SongShow Plus songs into the OpenLP database.
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from openlp.core.ui.wizard import WizardStrings
|
from openlp.core.ui.wizard import WizardStrings
|
||||||
@ -44,43 +45,36 @@ COPYRIGHT = 3
|
|||||||
CCLI_NO = 5
|
CCLI_NO = 5
|
||||||
VERSE = 12
|
VERSE = 12
|
||||||
CHORUS = 20
|
CHORUS = 20
|
||||||
|
BRIDGE = 24
|
||||||
TOPIC = 29
|
TOPIC = 29
|
||||||
COMMENTS = 30
|
COMMENTS = 30
|
||||||
VERSE_ORDER = 31
|
VERSE_ORDER = 31
|
||||||
SONG_BOOK = 35
|
SONG_BOOK = 35
|
||||||
SONG_NUMBER = 36
|
SONG_NUMBER = 36
|
||||||
CUSTOM_VERSE = 37
|
CUSTOM_VERSE = 37
|
||||||
BRIDGE = 24
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SongShowPlusImport(SongImport):
|
class SongShowPlusImport(SongImport):
|
||||||
"""
|
"""
|
||||||
The :class:`SongShowPlusImport` class provides the ability to import song
|
The :class:`SongShowPlusImport` class provides the ability to import song files from SongShow Plus.
|
||||||
files from SongShow Plus.
|
|
||||||
|
|
||||||
**SongShow Plus Song File Format:**
|
**SongShow Plus Song File Format:**
|
||||||
|
|
||||||
The SongShow Plus song file format is as follows:
|
The SongShow Plus song file format is as follows:
|
||||||
|
|
||||||
* Each piece of data in the song file has some information that precedes
|
* Each piece of data in the song file has some information that precedes it.
|
||||||
it.
|
|
||||||
* The general format of this data is as follows:
|
* The general format of this data is as follows:
|
||||||
4 Bytes, forming a 32 bit number, a key if you will, this describes what
|
4 Bytes, forming a 32 bit number, a key if you will, this describes what the data is (see blockKey below)
|
||||||
the data is (see blockKey below)
|
4 Bytes, forming a 32 bit number, which is the number of bytes until the next block starts
|
||||||
4 Bytes, forming a 32 bit number, which is the number of bytes until the
|
|
||||||
next block starts
|
|
||||||
1 Byte, which tells how many bytes follows
|
1 Byte, which tells how many bytes follows
|
||||||
1 or 4 Bytes, describes how long the string is, if its 1 byte, the string
|
1 or 4 Bytes, describes how long the string is, if its 1 byte, the string is less than 255
|
||||||
is less than 255
|
|
||||||
The next bytes are the actual data.
|
The next bytes are the actual data.
|
||||||
The next block of data follows on.
|
The next block of data follows on.
|
||||||
|
|
||||||
This description does differ for verses. Which includes extra bytes
|
This description does differ for verses. Which includes extra bytes stating the verse type or number. In some cases
|
||||||
stating the verse type or number. In some cases a "custom" verse is used,
|
a "custom" verse is used, in that case, this block will in include 2 strings, with the associated string length
|
||||||
in that case, this block will in include 2 strings, with the associated
|
descriptors. The first string is the name of the verse, the second is the verse content.
|
||||||
string length descriptors. The first string is the name of the verse, the
|
|
||||||
second is the verse content.
|
|
||||||
|
|
||||||
The file is ended with four null bytes.
|
The file is ended with four null bytes.
|
||||||
|
|
||||||
@ -88,8 +82,9 @@ class SongShowPlusImport(SongImport):
|
|||||||
|
|
||||||
* .sbsong
|
* .sbsong
|
||||||
"""
|
"""
|
||||||
otherList = {}
|
|
||||||
otherCount = 0
|
other_count = 0
|
||||||
|
other_list = {}
|
||||||
|
|
||||||
def __init__(self, manager, **kwargs):
|
def __init__(self, manager, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -107,9 +102,9 @@ class SongShowPlusImport(SongImport):
|
|||||||
for file in self.import_source:
|
for file in self.import_source:
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
return
|
return
|
||||||
self.sspVerseOrderList = []
|
self.ssp_verse_order_list = []
|
||||||
other_count = 0
|
self.other_count = 0
|
||||||
other_list = {}
|
self.other_list = {}
|
||||||
file_name = os.path.split(file)[1]
|
file_name = os.path.split(file)[1]
|
||||||
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % file_name, 0)
|
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % file_name, 0)
|
||||||
song_data = open(file, 'rb')
|
song_data = open(file, 'rb')
|
||||||
@ -162,34 +157,37 @@ class SongShowPlusImport(SongImport):
|
|||||||
elif block_key == COMMENTS:
|
elif block_key == COMMENTS:
|
||||||
self.comments = unicode(data, u'cp1252')
|
self.comments = unicode(data, u'cp1252')
|
||||||
elif block_key == VERSE_ORDER:
|
elif block_key == VERSE_ORDER:
|
||||||
verse_tag = self.toOpenLPVerseTag(data, True)
|
verse_tag = self.to_openlp_verse_tag(data, True)
|
||||||
if verse_tag:
|
if verse_tag:
|
||||||
if not isinstance(verse_tag, unicode):
|
if not isinstance(verse_tag, unicode):
|
||||||
verse_tag = unicode(verse_tag, u'cp1252')
|
verse_tag = unicode(verse_tag, u'cp1252')
|
||||||
self.sspVerseOrderList.append(verse_tag)
|
self.ssp_verse_order_list.append(verse_tag)
|
||||||
elif block_key == SONG_BOOK:
|
elif block_key == SONG_BOOK:
|
||||||
self.songBookName = unicode(data, u'cp1252')
|
self.songBookName = unicode(data, u'cp1252')
|
||||||
elif block_key == SONG_NUMBER:
|
elif block_key == SONG_NUMBER:
|
||||||
self.songNumber = ord(data)
|
self.songNumber = ord(data)
|
||||||
elif block_key == CUSTOM_VERSE:
|
elif block_key == CUSTOM_VERSE:
|
||||||
verse_tag = self.toOpenLPVerseTag(verse_name)
|
verse_tag = self.to_openlp_verse_tag(verse_name)
|
||||||
self.addVerse(unicode(data, u'cp1252'), verse_tag)
|
self.addVerse(unicode(data, u'cp1252'), verse_tag)
|
||||||
else:
|
else:
|
||||||
log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data))
|
log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data))
|
||||||
song_data.seek(next_block_starts)
|
song_data.seek(next_block_starts)
|
||||||
self.verseOrderList = self.sspVerseOrderList
|
self.verseOrderList = self.ssp_verse_order_list
|
||||||
song_data.close()
|
song_data.close()
|
||||||
if not self.finish():
|
if not self.finish():
|
||||||
self.logError(file)
|
self.logError(file)
|
||||||
|
|
||||||
def toOpenLPVerseTag(self, verse_name, ignore_unique=False):
|
def to_openlp_verse_tag(self, verse_name, ignore_unique=False):
|
||||||
if verse_name.find(" ") != -1:
|
# Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have
|
||||||
verse_parts = verse_name.split(" ")
|
# concept of part verses, so just ignore any non integers on the end (including floats))
|
||||||
verse_type = verse_parts[0]
|
match = re.match(r'(\D*)(\d+)', verse_name)
|
||||||
verse_number = verse_parts[1]
|
if match:
|
||||||
|
verse_type = match.group(1).strip()
|
||||||
|
verse_number = match.group(2)
|
||||||
else:
|
else:
|
||||||
|
# otherwise we assume number 1 and take the whole prefix as the verse tag
|
||||||
verse_type = verse_name
|
verse_type = verse_name
|
||||||
verse_number = "1"
|
verse_number = u'1'
|
||||||
verse_type = verse_type.lower()
|
verse_type = verse_type.lower()
|
||||||
if verse_type == "verse":
|
if verse_type == "verse":
|
||||||
verse_tag = VerseType.tags[VerseType.Verse]
|
verse_tag = VerseType.tags[VerseType.Verse]
|
||||||
@ -200,11 +198,11 @@ class SongShowPlusImport(SongImport):
|
|||||||
elif verse_type == "pre-chorus":
|
elif verse_type == "pre-chorus":
|
||||||
verse_tag = VerseType.tags[VerseType.PreChorus]
|
verse_tag = VerseType.tags[VerseType.PreChorus]
|
||||||
else:
|
else:
|
||||||
if verse_name not in self.otherList:
|
if verse_name not in self.other_list:
|
||||||
if ignore_unique:
|
if ignore_unique:
|
||||||
return None
|
return None
|
||||||
self.otherCount += 1
|
self.other_count += 1
|
||||||
self.otherList[verse_name] = str(self.otherCount)
|
self.other_list[verse_name] = str(self.other_count)
|
||||||
verse_tag = VerseType.tags[VerseType.Other]
|
verse_tag = VerseType.tags[VerseType.Other]
|
||||||
verse_number = self.otherList[verse_name]
|
verse_number = self.other_list[verse_name]
|
||||||
return verse_tag + verse_number
|
return verse_tag + verse_number
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
<file>author_maintenance.png</file>
|
<file>author_maintenance.png</file>
|
||||||
<file>topic_maintenance.png</file>
|
<file>topic_maintenance.png</file>
|
||||||
<file>song_author_edit.png</file>
|
<file>song_author_edit.png</file>
|
||||||
<file>song_topic_edit.png</file>
|
|
||||||
<file>song_book_edit.png</file>
|
<file>song_book_edit.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="images">
|
<qresource prefix="images">
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 830 B |
Binary file not shown.
Before Width: | Height: | Size: 352 KiB |
@ -83,6 +83,7 @@ MODULES = [
|
|||||||
'mako',
|
'mako',
|
||||||
'migrate',
|
'migrate',
|
||||||
'uno',
|
'uno',
|
||||||
|
'icu',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
@ -47,8 +47,7 @@ mv openlp/core/resources.py openlp/core/resources.py.old
|
|||||||
pyrcc4 -o openlp/core/resources.py.new resources/images/openlp-2.qrc
|
pyrcc4 -o openlp/core/resources.py.new resources/images/openlp-2.qrc
|
||||||
|
|
||||||
# Remove patch breaking lines
|
# Remove patch breaking lines
|
||||||
cat openlp/core/resources.py.new | sed '/# Created: /d;/# by: /d' \
|
cat openlp/core/resources.py.new | sed '/# Created: /d;/# by: /d' > openlp/core/resources.py
|
||||||
> openlp/core/resources.py
|
|
||||||
|
|
||||||
# Patch resources.py to OpenLP coding style
|
# Patch resources.py to OpenLP coding style
|
||||||
patch --posix -s openlp/core/resources.py scripts/resources.patch
|
patch --posix -s openlp/core/resources.py scripts/resources.patch
|
||||||
|
@ -5,7 +5,7 @@ from unittest import TestCase
|
|||||||
|
|
||||||
from mock import patch
|
from mock import patch
|
||||||
|
|
||||||
from openlp.core.utils import get_filesystem_encoding, _get_frozen_path
|
from openlp.core.utils import get_filesystem_encoding, _get_frozen_path, get_locale_key, get_natural_key
|
||||||
|
|
||||||
class TestUtils(TestCase):
|
class TestUtils(TestCase):
|
||||||
"""
|
"""
|
||||||
@ -56,3 +56,30 @@ class TestUtils(TestCase):
|
|||||||
# THEN: The frozen parameter is returned
|
# THEN: The frozen parameter is returned
|
||||||
assert _get_frozen_path(u'frozen', u'not frozen') == u'frozen', u'Should return "frozen"'
|
assert _get_frozen_path(u'frozen', u'not frozen') == u'frozen', u'Should return "frozen"'
|
||||||
|
|
||||||
|
def get_locale_key_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_locale_key(string) function
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language:
|
||||||
|
# GIVEN: The language is German
|
||||||
|
# 0x00C3 (A with diaresis) should be sorted as "A". 0x00DF (sharp s) should be sorted as "ss".
|
||||||
|
mocked_get_language.return_value = u'de'
|
||||||
|
unsorted_list = [u'Auszug', u'Aushang', u'\u00C4u\u00DFerung']
|
||||||
|
# WHEN: We sort the list and use get_locale_key() to generate the sorting keys
|
||||||
|
# THEN: We get a properly sorted list
|
||||||
|
test_passes = sorted(unsorted_list, key=get_locale_key) == [u'Aushang', u'\u00C4u\u00DFerung', u'Auszug']
|
||||||
|
assert test_passes, u'Strings should be sorted properly'
|
||||||
|
|
||||||
|
def get_natural_key_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_natural_key(string) function
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language:
|
||||||
|
# GIVEN: The language is English (a language, which sorts digits before letters)
|
||||||
|
mocked_get_language.return_value = u'en'
|
||||||
|
unsorted_list = [u'item 10a', u'item 3b', u'1st item']
|
||||||
|
# WHEN: We sort the list and use get_natural_key() to generate the sorting keys
|
||||||
|
# THEN: We get a properly sorted list
|
||||||
|
test_passes = sorted(unsorted_list, key=get_natural_key) == [u'1st item', u'item 3b', u'item 10a']
|
||||||
|
assert test_passes, u'Numbers should be sorted naturally'
|
||||||
|
|
||||||
|
235
tests/functional/openlp_plugins/songs/test_songshowplusimport.py
Normal file
235
tests/functional/openlp_plugins/songs/test_songshowplusimport.py
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
"""
|
||||||
|
This module contains tests for the SongShow Plus song importer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from unittest import TestCase
|
||||||
|
from mock import patch, MagicMock
|
||||||
|
|
||||||
|
from openlp.plugins.songs.lib import VerseType
|
||||||
|
from openlp.plugins.songs.lib.songshowplusimport import SongShowPlusImport
|
||||||
|
|
||||||
|
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'../../../resources/songshowplussongs'))
|
||||||
|
SONG_TEST_DATA = {u'Amazing Grace.sbsong':
|
||||||
|
{u'title': u'Amazing Grace (Demonstration)',
|
||||||
|
u'authors': [u'John Newton', u'Edwin Excell', u'John P. Rees'],
|
||||||
|
u'copyright': u'Public Domain ',
|
||||||
|
u'ccli_number': 22025,
|
||||||
|
u'verses':
|
||||||
|
[(u'Amazing grace! How sweet the sound!\r\nThat saved a wretch like me!\r\n'
|
||||||
|
u'I once was lost, but now am found;\r\nWas blind, but now I see.', u'v1'),
|
||||||
|
(u'\'Twas grace that taught my heart to fear,\r\nAnd grace my fears relieved.\r\n'
|
||||||
|
u'How precious did that grace appear,\r\nThe hour I first believed.', u'v2'),
|
||||||
|
(u'The Lord has promised good to me,\r\nHis Word my hope secures.\r\n'
|
||||||
|
u'He will my shield and portion be\r\nAs long as life endures.', u'v3'),
|
||||||
|
(u'Thro\' many dangers, toils and snares\r\nI have already come.\r\n'
|
||||||
|
u'\'Tis grace that brought me safe thus far,\r\nAnd grace will lead me home.', u'v4'),
|
||||||
|
(u'When we\'ve been there ten thousand years,\r\nBright shining as the sun,\r\n'
|
||||||
|
u'We\'ve no less days to sing God\'s praise,\r\nThan when we first begun.', u'v5')],
|
||||||
|
u'topics': [u'Assurance', u'Grace', u'Praise', u'Salvation'],
|
||||||
|
u'comments': u'\n\n\n',
|
||||||
|
u'song_book_name': u'Demonstration Songs',
|
||||||
|
u'song_number': 0,
|
||||||
|
u'verse_order_list': []},
|
||||||
|
u'Beautiful Garden Of Prayer.sbsong':
|
||||||
|
{u'title': u'Beautiful Garden Of Prayer (Demonstration)',
|
||||||
|
u'authors': [u'Eleanor Allen Schroll', u'James H. Fillmore'],
|
||||||
|
u'copyright': u'Public Domain ',
|
||||||
|
u'ccli_number': 60252,
|
||||||
|
u'verses':
|
||||||
|
[(u'There\'s a garden where Jesus is waiting,\r\nThere\'s a place that is wondrously fair.\r\n'
|
||||||
|
u'For it glows with the light of His presence,\r\n\'Tis the beautiful garden of prayer.', u'v1'),
|
||||||
|
(u'There\'s a garden where Jesus is waiting,\r\nAnd I go with my burden and care.\r\n'
|
||||||
|
u'Just to learn from His lips, words of comfort,\r\nIn the beautiful garden of prayer.', u'v2'),
|
||||||
|
(u'There\'s a garden where Jesus is waiting,\r\nAnd He bids you to come meet Him there,\r\n'
|
||||||
|
u'Just to bow and receive a new blessing,\r\nIn the beautiful garden of prayer.', u'v3'),
|
||||||
|
(u'O the beautiful garden, the garden of prayer,\r\nO the beautiful garden of prayer.\r\n'
|
||||||
|
u'There my Savior awaits, and He opens the gates\r\nTo the beautiful garden of prayer.', u'c1')],
|
||||||
|
u'topics': [u'Devotion', u'Prayer'],
|
||||||
|
u'comments': u'',
|
||||||
|
u'song_book_name': u'',
|
||||||
|
u'song_number': 0,
|
||||||
|
u'verse_order_list': []}}
|
||||||
|
|
||||||
|
|
||||||
|
class TestSongShowPlusImport(TestCase):
|
||||||
|
"""
|
||||||
|
Test the functions in the :mod:`songshowplusimport` module.
|
||||||
|
"""
|
||||||
|
def create_importer_test(self):
|
||||||
|
"""
|
||||||
|
Test creating an instance of the SongShow Plus file importer
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||||
|
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
|
||||||
|
mocked_manager = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: An importer object is created
|
||||||
|
importer = SongShowPlusImport(mocked_manager)
|
||||||
|
|
||||||
|
# THEN: The importer object should not be None
|
||||||
|
self.assertIsNotNone(importer, u'Import should not be none')
|
||||||
|
|
||||||
|
def invalid_import_source_test(self):
|
||||||
|
"""
|
||||||
|
Test SongShowPlusImport.doImport handles different invalid import_source values
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||||
|
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
|
||||||
|
mocked_manager = MagicMock()
|
||||||
|
mocked_import_wizard = MagicMock()
|
||||||
|
importer = SongShowPlusImport(mocked_manager)
|
||||||
|
importer.import_wizard = mocked_import_wizard
|
||||||
|
importer.stop_import_flag = True
|
||||||
|
|
||||||
|
# WHEN: Import source is not a list
|
||||||
|
for source in [u'not a list', 0]:
|
||||||
|
importer.import_source = source
|
||||||
|
|
||||||
|
# THEN: doImport should return none and the progress bar maximum should not be set.
|
||||||
|
self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
|
||||||
|
self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
|
||||||
|
u'setMaxium on import_wizard.progress_bar should not have been called')
|
||||||
|
|
||||||
|
def valid_import_source_test(self):
|
||||||
|
"""
|
||||||
|
Test SongShowPlusImport.doImport handles different invalid import_source values
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||||
|
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
|
||||||
|
mocked_manager = MagicMock()
|
||||||
|
mocked_import_wizard = MagicMock()
|
||||||
|
importer = SongShowPlusImport(mocked_manager)
|
||||||
|
importer.import_wizard = mocked_import_wizard
|
||||||
|
importer.stop_import_flag = True
|
||||||
|
|
||||||
|
# WHEN: Import source is a list
|
||||||
|
importer.import_source = [u'List', u'of', u'files']
|
||||||
|
|
||||||
|
# THEN: doImport should return none and the progress bar setMaximum should be called with the length of
|
||||||
|
# import_source.
|
||||||
|
self.assertIsNone(importer.doImport(),
|
||||||
|
u'doImport should return None when import_source is a list and stop_import_flag is True')
|
||||||
|
mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source))
|
||||||
|
|
||||||
|
def to_openlp_verse_tag_test(self):
|
||||||
|
"""
|
||||||
|
Test to_openlp_verse_tag method by simulating adding a verse
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||||
|
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
|
||||||
|
mocked_manager = MagicMock()
|
||||||
|
importer = SongShowPlusImport(mocked_manager)
|
||||||
|
|
||||||
|
# WHEN: Supplied with the following arguments replicating verses being added
|
||||||
|
test_values = [(u'Verse 1', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'Verse 2', VerseType.tags[VerseType.Verse] + u'2'),
|
||||||
|
(u'verse1', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'Verse', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'Verse1', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'chorus 1', VerseType.tags[VerseType.Chorus] + u'1'),
|
||||||
|
(u'bridge 1', VerseType.tags[VerseType.Bridge] + u'1'),
|
||||||
|
(u'pre-chorus 1', VerseType.tags[VerseType.PreChorus] + u'1'),
|
||||||
|
(u'different 1', VerseType.tags[VerseType.Other] + u'1'),
|
||||||
|
(u'random 1', VerseType.tags[VerseType.Other] + u'2')]
|
||||||
|
|
||||||
|
# THEN: The returned value should should correlate with the input arguments
|
||||||
|
for original_tag, openlp_tag in test_values:
|
||||||
|
self.assertEquals(importer.to_openlp_verse_tag(original_tag), openlp_tag,
|
||||||
|
u'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"'
|
||||||
|
% (openlp_tag, original_tag))
|
||||||
|
|
||||||
|
def to_openlp_verse_tag_verse_order_test(self):
|
||||||
|
"""
|
||||||
|
Test to_openlp_verse_tag method by simulating adding a verse to the verse order
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||||
|
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
|
||||||
|
mocked_manager = MagicMock()
|
||||||
|
importer = SongShowPlusImport(mocked_manager)
|
||||||
|
|
||||||
|
# WHEN: Supplied with the following arguments replicating a verse order being added
|
||||||
|
test_values = [(u'Verse 1', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'Verse 2', VerseType.tags[VerseType.Verse] + u'2'),
|
||||||
|
(u'verse1', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'Verse', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'Verse1', VerseType.tags[VerseType.Verse] + u'1'),
|
||||||
|
(u'chorus 1', VerseType.tags[VerseType.Chorus] + u'1'),
|
||||||
|
(u'bridge 1', VerseType.tags[VerseType.Bridge] + u'1'),
|
||||||
|
(u'pre-chorus 1', VerseType.tags[VerseType.PreChorus] + u'1'),
|
||||||
|
(u'different 1', VerseType.tags[VerseType.Other] + u'1'),
|
||||||
|
(u'random 1', VerseType.tags[VerseType.Other] + u'2'),
|
||||||
|
(u'unused 2', None)]
|
||||||
|
|
||||||
|
# THEN: The returned value should should correlate with the input arguments
|
||||||
|
for original_tag, openlp_tag in test_values:
|
||||||
|
self.assertEquals(importer.to_openlp_verse_tag(original_tag, ignore_unique=True), openlp_tag,
|
||||||
|
u'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"'
|
||||||
|
% (openlp_tag, original_tag))
|
||||||
|
|
||||||
|
def file_import_test(self):
|
||||||
|
"""
|
||||||
|
Test the actual import of real song files and check that the imported data is correct.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard",
|
||||||
|
# and mocked out "author", "add_copyright", "add_verse", "finish" methods.
|
||||||
|
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
|
||||||
|
for song_file in SONG_TEST_DATA:
|
||||||
|
mocked_manager = MagicMock()
|
||||||
|
mocked_import_wizard = MagicMock()
|
||||||
|
mocked_parse_author = MagicMock()
|
||||||
|
mocked_add_copyright = MagicMock()
|
||||||
|
mocked_add_verse = MagicMock()
|
||||||
|
mocked_finish = MagicMock()
|
||||||
|
mocked_finish.return_value = True
|
||||||
|
importer = SongShowPlusImport(mocked_manager)
|
||||||
|
importer.import_wizard = mocked_import_wizard
|
||||||
|
importer.stop_import_flag = False
|
||||||
|
importer.parse_author = mocked_parse_author
|
||||||
|
importer.addCopyright = mocked_add_copyright
|
||||||
|
importer.addVerse = mocked_add_verse
|
||||||
|
importer.finish = mocked_finish
|
||||||
|
importer.topics = []
|
||||||
|
|
||||||
|
# WHEN: Importing each file
|
||||||
|
importer.import_source = [os.path.join(TEST_PATH, song_file)]
|
||||||
|
title = SONG_TEST_DATA[song_file][u'title']
|
||||||
|
author_calls = SONG_TEST_DATA[song_file][u'authors']
|
||||||
|
song_copyright = SONG_TEST_DATA[song_file][u'copyright']
|
||||||
|
ccli_number = SONG_TEST_DATA[song_file][u'ccli_number']
|
||||||
|
add_verse_calls = SONG_TEST_DATA[song_file][u'verses']
|
||||||
|
topics = SONG_TEST_DATA[song_file][u'topics']
|
||||||
|
comments = SONG_TEST_DATA[song_file][u'comments']
|
||||||
|
song_book_name = SONG_TEST_DATA[song_file][u'song_book_name']
|
||||||
|
song_number = SONG_TEST_DATA[song_file][u'song_number']
|
||||||
|
verse_order_list = SONG_TEST_DATA[song_file][u'verse_order_list']
|
||||||
|
|
||||||
|
# THEN: doImport should return none, the song data should be as expected, and finish should have been
|
||||||
|
# called.
|
||||||
|
self.assertIsNone(importer.doImport(), u'doImport should return None when it has completed')
|
||||||
|
self.assertEquals(importer.title, title, u'title for %s should be "%s"' % (song_file, title))
|
||||||
|
for author in author_calls:
|
||||||
|
mocked_parse_author.assert_any_call(author)
|
||||||
|
if song_copyright:
|
||||||
|
mocked_add_copyright.assert_called_with(song_copyright)
|
||||||
|
if ccli_number:
|
||||||
|
self.assertEquals(importer.ccliNumber, ccli_number, u'ccliNumber for %s should be %s'
|
||||||
|
% (song_file, ccli_number))
|
||||||
|
for verse_text, verse_tag in add_verse_calls:
|
||||||
|
mocked_add_verse.assert_any_call(verse_text, verse_tag)
|
||||||
|
if topics:
|
||||||
|
self.assertEquals(importer.topics, topics, u'topics for %s should be %s' % (song_file, topics))
|
||||||
|
if comments:
|
||||||
|
self.assertEquals(importer.comments, comments, u'comments for %s should be "%s"'
|
||||||
|
% (song_file, comments))
|
||||||
|
if song_book_name:
|
||||||
|
self.assertEquals(importer.songBookName, song_book_name, u'songBookName for %s should be "%s"'
|
||||||
|
% (song_file, song_book_name))
|
||||||
|
if song_number:
|
||||||
|
self.assertEquals(importer.songNumber, song_number, u'songNumber for %s should be %s'
|
||||||
|
% (song_file, song_number))
|
||||||
|
if verse_order_list:
|
||||||
|
self.assertEquals(importer.verseOrderList, [], u'verseOrderList for %s should be %s'
|
||||||
|
% (song_file, verse_order_list))
|
||||||
|
mocked_finish.assert_called_with()
|
@ -3,11 +3,11 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from mock import MagicMock, patch
|
from mock import MagicMock, Mock, patch
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
from openlp.core.lib import Registry, ScreenList
|
from openlp.core.lib import Registry, ScreenList, ServiceItem
|
||||||
from openlp.core.ui.mainwindow import MainWindow
|
from openlp.core.ui.mainwindow import MainWindow
|
||||||
|
|
||||||
|
|
||||||
@ -42,3 +42,44 @@ class TestServiceManager(TestCase):
|
|||||||
# THEN the count of items should be zero
|
# THEN the count of items should be zero
|
||||||
self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0,
|
self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0,
|
||||||
u'The service manager list should be empty ')
|
u'The service manager list should be empty ')
|
||||||
|
|
||||||
|
def context_menu_test(self):
|
||||||
|
"""
|
||||||
|
Test the context_menu() method.
|
||||||
|
"""
|
||||||
|
# GIVEN: A service item added
|
||||||
|
with patch(u'PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
|
patch(u'PyQt4.QtGui.QWidget.mapToGlobal') as mocked_map_to_global, \
|
||||||
|
patch(u'PyQt4.QtGui.QMenu.exec_') as mocked_exec:
|
||||||
|
mocked_item = MagicMock()
|
||||||
|
mocked_item.parent.return_value = None
|
||||||
|
mocked_item_at_method.return_value = mocked_item
|
||||||
|
# We want 1 to be returned for the position
|
||||||
|
mocked_item.data.return_value = 1
|
||||||
|
# A service item without capabilities.
|
||||||
|
service_item = ServiceItem()
|
||||||
|
self.service_manager.service_items = [{u'service_item': service_item}]
|
||||||
|
q_point = None
|
||||||
|
# Mocked actions.
|
||||||
|
self.service_manager.edit_action.setVisible = Mock()
|
||||||
|
self.service_manager.create_custom_action.setVisible = Mock()
|
||||||
|
self.service_manager.maintain_action.setVisible = Mock()
|
||||||
|
self.service_manager.notes_action.setVisible = Mock()
|
||||||
|
self.service_manager.time_action.setVisible = Mock()
|
||||||
|
self.service_manager.auto_start_action.setVisible = Mock()
|
||||||
|
|
||||||
|
# WHEN: Show the context menu.
|
||||||
|
self.service_manager.context_menu(q_point)
|
||||||
|
|
||||||
|
# THEN: The following actions should be not visible.
|
||||||
|
self.service_manager.edit_action.setVisible.assert_called_once_with(False), \
|
||||||
|
u'The action should be set invisible.'
|
||||||
|
self.service_manager.create_custom_action.setVisible.assert_called_once_with(False), \
|
||||||
|
u'The action should be set invisible.'
|
||||||
|
self.service_manager.maintain_action.setVisible.assert_called_once_with(False), \
|
||||||
|
u'The action should be set invisible.'
|
||||||
|
self.service_manager.notes_action.setVisible.assert_called_with(True), u'The action should be set visible.'
|
||||||
|
self.service_manager.time_action.setVisible.assert_called_once_with(False), \
|
||||||
|
u'The action should be set invisible.'
|
||||||
|
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
||||||
|
u'The action should be set invisible.'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Module to test the custom edit form.
|
Module to test the EditCustomForm.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from mock import MagicMock, patch
|
from mock import MagicMock, patch
|
||||||
@ -12,7 +12,7 @@ from openlp.plugins.custom.lib.mediaitem import CustomMediaItem
|
|||||||
from openlp.plugins.custom.forms.editcustomform import EditCustomForm
|
from openlp.plugins.custom.forms.editcustomform import EditCustomForm
|
||||||
|
|
||||||
|
|
||||||
class TestCustomFrom(TestCase):
|
class TestEditCustomForm(TestCase):
|
||||||
"""
|
"""
|
||||||
Test the EditCustomForm.
|
Test the EditCustomForm.
|
||||||
"""
|
"""
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
Module to test the EditCustomSlideForm.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
from mock import MagicMock, patch
|
||||||
|
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
|
from openlp.core.lib import Registry
|
||||||
|
from openlp.plugins.custom.forms.editcustomslideform import EditCustomSlideForm
|
||||||
|
|
||||||
|
|
||||||
|
class TestEditCustomSlideForm(TestCase):
|
||||||
|
"""
|
||||||
|
Test the EditCustomSlideForm.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create the UI
|
||||||
|
"""
|
||||||
|
Registry.create()
|
||||||
|
self.app = QtGui.QApplication([])
|
||||||
|
self.main_window = QtGui.QMainWindow()
|
||||||
|
Registry().register(u'main_window', self.main_window)
|
||||||
|
self.form = EditCustomSlideForm()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Delete all the C++ objects at the end so that we don't have a segfault
|
||||||
|
"""
|
||||||
|
del self.form
|
||||||
|
del self.main_window
|
||||||
|
del self.app
|
||||||
|
|
||||||
|
def basic_test(self):
|
||||||
|
"""
|
||||||
|
Test if the dialog is correctly set up.
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked QDialog.exec_() method
|
||||||
|
with patch(u'PyQt4.QtGui.QDialog.exec_') as mocked_exec:
|
||||||
|
# WHEN: Show the dialog.
|
||||||
|
self.form.exec_()
|
||||||
|
|
||||||
|
# THEN: The dialog should be empty.
|
||||||
|
assert self.form.slide_text_edit.toPlainText() == u'', u'There should not be any text in the text editor.'
|
||||||
|
|
||||||
|
def set_text_test(self):
|
||||||
|
"""
|
||||||
|
Test the set_text() method.
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked QDialog.exec_() method
|
||||||
|
with patch(u'PyQt4.QtGui.QDialog.exec_') as mocked_exec:
|
||||||
|
mocked_set_focus = MagicMock()
|
||||||
|
self.form.slide_text_edit.setFocus = mocked_set_focus
|
||||||
|
wanted_text = u'THIS TEXT SHOULD BE SHOWN.'
|
||||||
|
|
||||||
|
# WHEN: Show the dialog and set the text.
|
||||||
|
self.form.exec_()
|
||||||
|
self.form.set_text(wanted_text)
|
||||||
|
|
||||||
|
# THEN: The dialog should show the text.
|
||||||
|
assert self.form.slide_text_edit.toPlainText() == wanted_text, \
|
||||||
|
u'The text editor should show the correct text.'
|
||||||
|
|
||||||
|
# THEN: The dialog should have focus.
|
||||||
|
mocked_set_focus.assert_called_with()
|
||||||
|
|
BIN
tests/resources/songshowplussongs/Amazing Grace.sbsong
Normal file
BIN
tests/resources/songshowplussongs/Amazing Grace.sbsong
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user