This commit is contained in:
Tim Bentley 2014-07-08 19:05:24 +01:00
commit b546b6b825
70 changed files with 2177 additions and 417 deletions

View File

@ -72,15 +72,15 @@ class AppLocation(object):
:param dir_type: The directory type you want, for instance the data directory. Default *AppLocation.AppDir* :param dir_type: The directory type you want, for instance the data directory. Default *AppLocation.AppDir*
""" """
if dir_type == AppLocation.AppDir: if dir_type == AppLocation.AppDir:
return get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0]) return get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), os.path.dirname(openlp.__file__))
elif dir_type == AppLocation.PluginsDir: elif dir_type == AppLocation.PluginsDir:
app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) app_path = os.path.abspath(os.path.dirname(sys.argv[0]))
return get_frozen_path(os.path.join(app_path, 'plugins'), return get_frozen_path(os.path.join(app_path, 'plugins'),
os.path.join(os.path.split(openlp.__file__)[0], 'plugins')) os.path.join(os.path.dirname(openlp.__file__), 'plugins'))
elif dir_type == AppLocation.VersionDir: elif dir_type == AppLocation.VersionDir:
return get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0]) return get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), os.path.dirname(openlp.__file__))
elif dir_type == AppLocation.LanguageDir: elif dir_type == AppLocation.LanguageDir:
app_path = get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), _get_os_dir_path(dir_type)) app_path = get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), _get_os_dir_path(dir_type))
return os.path.join(app_path, 'i18n') return os.path.join(app_path, 'i18n')
elif dir_type == AppLocation.DataDir and AppLocation.BaseDir: elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
return os.path.join(AppLocation.BaseDir, 'data') return os.path.join(AppLocation.BaseDir, 'data')
@ -140,18 +140,22 @@ def _get_os_dir_path(dir_type):
""" """
Return a path based on which OS and environment we are running in. Return a path based on which OS and environment we are running in.
""" """
# If running from source, return the language directory from the source directory
if dir_type == AppLocation.LanguageDir:
directory = os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources'))
if os.path.exists(directory):
return directory
if sys.platform == 'win32': if sys.platform == 'win32':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data') return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data')
elif dir_type == AppLocation.LanguageDir: elif dir_type == AppLocation.LanguageDir:
return os.path.split(openlp.__file__)[0] return os.path.dirname(openlp.__file__)
return os.path.join(str(os.getenv('APPDATA')), 'openlp') return os.path.join(str(os.getenv('APPDATA')), 'openlp')
elif sys.platform == 'darwin': elif sys.platform == 'darwin':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(str(os.getenv('HOME')), return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp', 'Data')
'Library', 'Application Support', 'openlp', 'Data')
elif dir_type == AppLocation.LanguageDir: elif dir_type == AppLocation.LanguageDir:
return os.path.split(openlp.__file__)[0] return os.path.dirname(openlp.__file__)
return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp') return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp')
else: else:
if dir_type == AppLocation.LanguageDir: if dir_type == AppLocation.LanguageDir:

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# 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 #

View File

@ -82,11 +82,6 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
present_plugin_dir = os.path.join(self.base_path, 'presentations') present_plugin_dir = os.path.join(self.base_path, 'presentations')
self.log_debug('finding plugins in %s at depth %d' % (self.base_path, start_depth)) self.log_debug('finding plugins in %s at depth %d' % (self.base_path, start_depth))
for root, dirs, files in os.walk(self.base_path): for root, dirs, files in os.walk(self.base_path):
if sys.platform == 'darwin' and root.startswith(present_plugin_dir):
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it. The following code will ignore files from the presentation plugin directory
# and thereby never import the plugin.
continue
for name in files: for name in files:
if name.endswith('.py') and not name.startswith('__'): if name.endswith('.py') and not name.startswith('__'):
path = os.path.abspath(os.path.join(root, name)) path = os.path.abspath(os.path.join(root, name))

View File

@ -412,9 +412,6 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...')) self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...'))
self._set_plugin_status(self.songs_check_box, 'songs/status') self._set_plugin_status(self.songs_check_box, 'songs/status')
self._set_plugin_status(self.bible_check_box, 'bibles/status') self._set_plugin_status(self.bible_check_box, 'bibles/status')
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it.
if sys.platform != 'darwin':
self._set_plugin_status(self.presentation_check_box, 'presentations/status') self._set_plugin_status(self.presentation_check_box, 'presentations/status')
self._set_plugin_status(self.image_check_box, 'images/status') self._set_plugin_status(self.image_check_box, 'images/status')
self._set_plugin_status(self.media_check_box, 'media/status') self._set_plugin_status(self.media_check_box, 'media/status')

View File

@ -95,9 +95,6 @@ class Ui_FirstTimeWizard(object):
self.image_check_box.setChecked(True) self.image_check_box.setChecked(True)
self.image_check_box.setObjectName('image_check_box') self.image_check_box.setObjectName('image_check_box')
self.plugin_layout.addWidget(self.image_check_box) self.plugin_layout.addWidget(self.image_check_box)
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it.
if sys.platform != 'darwin':
self.presentation_check_box = QtGui.QCheckBox(self.plugin_page) self.presentation_check_box = QtGui.QCheckBox(self.plugin_page)
self.presentation_check_box.setChecked(True) self.presentation_check_box.setChecked(True)
self.presentation_check_box.setObjectName('presentation_check_box') self.presentation_check_box.setObjectName('presentation_check_box')
@ -222,9 +219,6 @@ class Ui_FirstTimeWizard(object):
self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides')) self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides'))
self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bible')) self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))
self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Images')) self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Images'))
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it.
if sys.platform != 'darwin':
self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations')) self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations'))
self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)')) self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)'))
self.remote_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access')) self.remote_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access'))

View File

@ -91,10 +91,9 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog, FormattingTagCont
""" """
new_row = self.tag_table_widget.rowCount() new_row = self.tag_table_widget.rowCount()
self.tag_table_widget.insertRow(new_row) self.tag_table_widget.insertRow(new_row)
self.tag_table_widget.setItem(new_row, 0, self.tag_table_widget.setItem(new_row, 0, QtGui.QTableWidgetItem(translate('OpenLP.FormattingTagForm',
QtGui.QTableWidgetItem(translate('OpenLP.FormattingTagForm', 'New Tag%s') 'New Tag %d' % new_row)))
% str(new_row))) self.tag_table_widget.setItem(new_row, 1, QtGui.QTableWidgetItem('n%d' % new_row))
self.tag_table_widget.setItem(new_row, 1, QtGui.QTableWidgetItem('n%s' % str(new_row)))
self.tag_table_widget.setItem(new_row, 2, self.tag_table_widget.setItem(new_row, 2,
QtGui.QTableWidgetItem(translate('OpenLP.FormattingTagForm', '<HTML here>'))) QtGui.QTableWidgetItem(translate('OpenLP.FormattingTagForm', '<HTML here>')))
self.tag_table_widget.setItem(new_row, 3, QtGui.QTableWidgetItem('')) self.tag_table_widget.setItem(new_row, 3, QtGui.QTableWidgetItem(''))

View File

@ -48,7 +48,7 @@ import sys
from inspect import getargspec from inspect import getargspec
__version__ = "N/A" __version__ = "N/A"
build_date = "Tue Jul 2 10:35:53 2013" build_date = "Wed Jun 25 13:46:01 2014"
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
str = str str = str
@ -110,7 +110,11 @@ def find_lib():
p = find_library('libvlc.dll') p = find_library('libvlc.dll')
if p is None: if p is None:
try: # some registry settings try: # some registry settings
import _winreg as w # leaner than win32api, win32con # leaner than win32api, win32con
if PYTHON3:
import winreg as w
else:
import _winreg as w
for r in w.HKEY_LOCAL_MACHINE, w.HKEY_CURRENT_USER: for r in w.HKEY_LOCAL_MACHINE, w.HKEY_CURRENT_USER:
try: try:
r = w.OpenKey(r, 'Software\\VideoLAN\\VLC') r = w.OpenKey(r, 'Software\\VideoLAN\\VLC')
@ -365,6 +369,7 @@ class EventType(_Enum):
3: 'MediaParsedChanged', 3: 'MediaParsedChanged',
4: 'MediaFreed', 4: 'MediaFreed',
5: 'MediaStateChanged', 5: 'MediaStateChanged',
6: 'MediaSubItemTreeAdded',
0x100: 'MediaPlayerMediaChanged', 0x100: 'MediaPlayerMediaChanged',
257: 'MediaPlayerNothingSpecial', 257: 'MediaPlayerNothingSpecial',
258: 'MediaPlayerOpening', 258: 'MediaPlayerOpening',
@ -384,6 +389,7 @@ class EventType(_Enum):
272: 'MediaPlayerSnapshotTaken', 272: 'MediaPlayerSnapshotTaken',
273: 'MediaPlayerLengthChanged', 273: 'MediaPlayerLengthChanged',
274: 'MediaPlayerVout', 274: 'MediaPlayerVout',
275: 'MediaPlayerScrambledChanged',
0x200: 'MediaListItemAdded', 0x200: 'MediaListItemAdded',
513: 'MediaListWillAddItem', 513: 'MediaListWillAddItem',
514: 'MediaListItemDeleted', 514: 'MediaListItemDeleted',
@ -439,6 +445,7 @@ EventType.MediaPlayerPausableChanged = EventType(270)
EventType.MediaPlayerPaused = EventType(261) EventType.MediaPlayerPaused = EventType(261)
EventType.MediaPlayerPlaying = EventType(260) EventType.MediaPlayerPlaying = EventType(260)
EventType.MediaPlayerPositionChanged = EventType(268) EventType.MediaPlayerPositionChanged = EventType(268)
EventType.MediaPlayerScrambledChanged = EventType(275)
EventType.MediaPlayerSeekableChanged = EventType(269) EventType.MediaPlayerSeekableChanged = EventType(269)
EventType.MediaPlayerSnapshotTaken = EventType(272) EventType.MediaPlayerSnapshotTaken = EventType(272)
EventType.MediaPlayerStopped = EventType(262) EventType.MediaPlayerStopped = EventType(262)
@ -447,6 +454,7 @@ EventType.MediaPlayerTitleChanged = EventType(271)
EventType.MediaPlayerVout = EventType(274) EventType.MediaPlayerVout = EventType(274)
EventType.MediaStateChanged = EventType(5) EventType.MediaStateChanged = EventType(5)
EventType.MediaSubItemAdded = EventType(1) EventType.MediaSubItemAdded = EventType(1)
EventType.MediaSubItemTreeAdded = EventType(6)
EventType.VlmMediaAdded = EventType(0x600) EventType.VlmMediaAdded = EventType(0x600)
EventType.VlmMediaChanged = EventType(1538) EventType.VlmMediaChanged = EventType(1538)
EventType.VlmMediaInstanceStarted = EventType(1539) EventType.VlmMediaInstanceStarted = EventType(1539)
@ -480,23 +488,35 @@ class Meta(_Enum):
14: 'EncodedBy', 14: 'EncodedBy',
15: 'ArtworkURL', 15: 'ArtworkURL',
16: 'TrackID', 16: 'TrackID',
17: 'TrackTotal',
18: 'Director',
19: 'Season',
20: 'Episode',
21: 'ShowName',
22: 'Actors',
} }
Meta.Actors = Meta(22)
Meta.Album = Meta(4) Meta.Album = Meta(4)
Meta.Artist = Meta(1) Meta.Artist = Meta(1)
Meta.ArtworkURL = Meta(15) Meta.ArtworkURL = Meta(15)
Meta.Copyright = Meta(3) Meta.Copyright = Meta(3)
Meta.Date = Meta(8) Meta.Date = Meta(8)
Meta.Description = Meta(6) Meta.Description = Meta(6)
Meta.Director = Meta(18)
Meta.EncodedBy = Meta(14) Meta.EncodedBy = Meta(14)
Meta.Episode = Meta(20)
Meta.Genre = Meta(2) Meta.Genre = Meta(2)
Meta.Language = Meta(11) Meta.Language = Meta(11)
Meta.NowPlaying = Meta(12) Meta.NowPlaying = Meta(12)
Meta.Publisher = Meta(13) Meta.Publisher = Meta(13)
Meta.Rating = Meta(7) Meta.Rating = Meta(7)
Meta.Season = Meta(19)
Meta.Setting = Meta(9) Meta.Setting = Meta(9)
Meta.ShowName = Meta(21)
Meta.Title = Meta(0) Meta.Title = Meta(0)
Meta.TrackID = Meta(16) Meta.TrackID = Meta(16)
Meta.TrackNumber = Meta(5) Meta.TrackNumber = Meta(5)
Meta.TrackTotal = Meta(17)
Meta.URL = Meta(10) Meta.URL = Meta(10)
class State(_Enum): class State(_Enum):
@ -594,6 +614,32 @@ NavigateMode.left = NavigateMode(3)
NavigateMode.right = NavigateMode(4) NavigateMode.right = NavigateMode(4)
NavigateMode.up = NavigateMode(1) NavigateMode.up = NavigateMode(1)
class Position(_Enum):
'''Enumeration of values used to set position (e.g. of video title).
'''
_enum_names_ = {
-1: 'disable',
0: 'center',
1: 'left',
2: 'right',
3: 'top',
4: 'left',
5: 'right',
6: 'bottom',
7: 'left',
8: 'right',
}
Position.bottom = Position(6)
Position.center = Position(0)
Position.disable = Position(-1)
Position.left = Position(1)
Position.left = Position(4)
Position.left = Position(7)
Position.right = Position(2)
Position.right = Position(5)
Position.right = Position(8)
Position.top = Position(3)
class VideoLogoOption(_Enum): class VideoLogoOption(_Enum):
'''Option values for libvlc_video_{get,set}_logo_{int,string}. '''Option values for libvlc_video_{get,set}_logo_{int,string}.
''' '''
@ -685,7 +731,7 @@ 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_set}() \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 ctx message context (meta-information 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.
@ -828,7 +874,7 @@ class CallbackDecorators(object):
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_set}() \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 ctx message context (meta-information 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.
@ -1432,6 +1478,16 @@ class Instance(_Ctype):
''' '''
return libvlc_set_user_agent(self, str_to_bytes(name), str_to_bytes(http)) return libvlc_set_user_agent(self, str_to_bytes(name), str_to_bytes(http))
def set_app_id(self, id, version, icon):
'''Sets some meta-information about the application.
See also L{set_user_agent}().
@param id: Java-style application identifier, e.g. "com.acme.foobar".
@param version: application version numbers, e.g. "1.2.3".
@param icon: application icon name, e.g. "foobar".
@version: LibVLC 2.1.0 or later.
'''
return libvlc_set_app_id(self, str_to_bytes(id), str_to_bytes(version), str_to_bytes(icon))
def log_unset(self): def log_unset(self):
'''Unsets the logging callback for a LibVLC instance. This is rarely needed: '''Unsets the logging callback for a LibVLC instance. This is rarely needed:
the callback is implicitly unset when the instance is destroyed. the callback is implicitly unset when the instance is destroyed.
@ -1521,13 +1577,13 @@ class Instance(_Ctype):
return libvlc_media_library_new(self) return libvlc_media_library_new(self)
def audio_output_list_get(self): def audio_output_list_get(self):
'''Gets the list of available audio outputs. '''Gets the list of available audio output modules.
@return: list of available audio outputs. It must be freed it with In case of error, NULL is returned. @return: list of available audio outputs. It must be freed it with In case of error, NULL is returned.
''' '''
return libvlc_audio_output_list_get(self) return libvlc_audio_output_list_get(self)
def audio_output_device_list_get(self, aout): def audio_output_device_list_get(self, aout):
'''Gets a list of audio output devices for a given audio output. '''Gets a list of audio output devices for a given audio output module,
See L{audio_output_device_set}(). See L{audio_output_device_set}().
@note: Not all audio outputs support this. In particular, an empty (NULL) @note: Not all audio outputs support this. In particular, an empty (NULL)
list of devices does B{not} imply that the specified audio output does list of devices does B{not} imply that the specified audio output does
@ -1790,6 +1846,19 @@ class Media(_Ctype):
for o in options: for o in options:
self.add_option(o) self.add_option(o)
def tracks_get(self):
"""Get media descriptor's elementary streams description
Note, you need to call L{parse}() or play the media at least once
before calling this function.
Not doing this will result in an empty array.
The result must be freed with L{tracks_release}.
@version: LibVLC 2.1.0 and later.
"""
mediaTrack_pp = ctypes.POINTER(MediaTrack)()
n = libvlc_media_tracks_get(self, byref(mediaTrack_pp))
info = cast(ctypes.mediaTrack_pp, ctypes.POINTER(ctypes.POINTER(MediaTrack) * n))
return info
def add_option(self, psz_options): def add_option(self, psz_options):
'''Add an option to the media. '''Add an option to the media.
@ -1962,17 +2031,6 @@ class Media(_Ctype):
''' '''
return libvlc_media_get_user_data(self) return libvlc_media_get_user_data(self)
def tracks_get(self, tracks):
'''Get media descriptor's elementary streams description
Note, you need to call L{parse}() or play the media at least once
before calling this function.
Not doing this will result in an empty array.
@param tracks: address to store an allocated array of Elementary Streams descriptions (must be freed with L{tracks_release}.
@return: the number of Elementary Streams (zero on error).
@version: LibVLC 2.1.0 and later.
'''
return libvlc_media_tracks_get(self, tracks)
def player_new_from_media(self): def player_new_from_media(self):
'''Create a Media Player object from a Media. '''Create a Media Player object from a Media.
@return: a new media player object, or NULL on error. @return: a new media player object, or NULL on error.
@ -2796,6 +2854,13 @@ class MediaPlayer(_Ctype):
''' '''
return libvlc_media_player_can_pause(self) return libvlc_media_player_can_pause(self)
def program_scrambled(self):
'''Check if the current program is scrambled.
@return: true if the current program is scrambled \libvlc_return_bool.
@version: LibVLC 2.2.0 or later.
'''
return libvlc_media_player_program_scrambled(self)
def next_frame(self): def next_frame(self):
'''Display the next frame (if supported). '''Display the next frame (if supported).
''' '''
@ -2808,6 +2873,14 @@ class MediaPlayer(_Ctype):
''' '''
return libvlc_media_player_navigate(self, navigate) return libvlc_media_player_navigate(self, navigate)
def set_video_title_display(self, position, timeout):
'''Set if, and how, the video title will be shown when media is played.
@param position: position at which to display the title, or libvlc_position_disable to prevent the title from being displayed.
@param timeout: title display timeout in milliseconds (ignored if libvlc_position_disable).
@version: libVLC 2.1.0 or later.
'''
return libvlc_media_player_set_video_title_display(self, position, timeout)
def toggle_fullscreen(self): def toggle_fullscreen(self):
'''Toggle fullscreen status on non-embedded video outputs. '''Toggle fullscreen status on non-embedded video outputs.
@warning: The same limitations applies to this function @warning: The same limitations applies to this function
@ -3083,7 +3156,7 @@ class MediaPlayer(_Ctype):
return libvlc_video_set_adjust_float(self, option, value) return libvlc_video_set_adjust_float(self, option, value)
def audio_output_set(self, psz_name): def audio_output_set(self, psz_name):
'''Sets the audio output. '''Selects an audio output module.
@note: Any change will take be effect only after playback is stopped and @note: Any change will take be effect only after playback is stopped and
restarted. Audio output cannot be changed while playing. restarted. Audio output cannot be changed while playing.
@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}.
@ -3091,21 +3164,46 @@ class MediaPlayer(_Ctype):
''' '''
return libvlc_audio_output_set(self, str_to_bytes(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_enum(self):
'''Configures an explicit audio output device for a given audio output plugin. '''Gets a list of potential audio output devices,
A list of possible devices can be obtained with See L{audio_output_device_set}().
@note: Not all audio outputs support enumerating devices.
The audio output may be functional even if the list is empty (NULL).
@note: The list may not be exhaustive.
@warning: Some audio output devices in the list might not actually work in
some circumstances. By default, it is recommended to not specify any
explicit audio device.
@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.2.0 or later.
'''
return libvlc_audio_output_device_enum(self)
def audio_output_device_set(self, module, device_id):
'''Configures an explicit audio output device.
If the module paramater is NULL, audio output will be moved to the device
specified by the device identifier string immediately. This is the
recommended usage.
A list of adequate potential device strings can be obtained with
L{audio_output_device_enum}().
However passing NULL is supported in LibVLC version 2.2.0 and later only;
in earlier versions, this function would have no effects when the module
parameter was NULL.
If the module parameter is not NULL, the device parameter of the
corresponding audio output, if it exists, will be set to the specified
string. Note that some audio output modules do not have such a parameter
(notably MMDevice and PulseAudio).
A list of adequate potential device strings can be obtained with
L{audio_output_device_list_get}(). L{audio_output_device_list_get}().
@note: This function does not select the specified audio output plugin. @note: This function does not select the specified audio output plugin.
L{audio_output_set}() is used for that purpose. L{audio_output_set}() is used for that purpose.
@warning: The syntax for the device parameter depends on the audio output. @warning: The syntax for the device parameter depends on the audio output.
This is not portable. Only use this function if you know what you are doing. Some audio output modules require further parameters (e.g. a channels map
Some audio outputs do not support this function (e.g. PulseAudio, WASAPI). in the case of ALSA).
Some audio outputs require further parameters (e.g. ALSA: channels map). @param module: If NULL, current audio output module. if non-NULL, name of audio output module.
@param psz_audio_output: - name of audio output, See L{AudioOutput}. @param device_id: device identifier string.
@param psz_device_id: device. @return: Nothing. Errors are ignored (this is a design bug).
@return: Nothing. Errors are ignored.
''' '''
return libvlc_audio_output_device_set(self, str_to_bytes(psz_audio_output), str_to_bytes(psz_device_id)) return libvlc_audio_output_device_set(self, str_to_bytes(module), str_to_bytes(device_id))
def audio_toggle_mute(self): def audio_toggle_mute(self):
'''Toggle mute status. '''Toggle mute status.
@ -3184,6 +3282,28 @@ class MediaPlayer(_Ctype):
''' '''
return libvlc_audio_set_delay(self, i_delay) return libvlc_audio_set_delay(self, i_delay)
def set_equalizer(self, p_equalizer):
'''Apply new equalizer settings to a media player.
The equalizer is first created by invoking L{audio_equalizer_new}() or
L{audio_equalizer_new_from_preset}().
It is possible to apply new equalizer settings to a media player whether the media
player is currently playing media or not.
Invoking this method will immediately apply the new equalizer settings to the audio
output of the currently playing media if there is any.
If there is no currently playing media, the new equalizer settings will be applied
later if and when new media is played.
Equalizer settings will automatically be applied to subsequently played media.
To disable the equalizer for a media player invoke this method passing NULL for the
p_equalizer parameter.
The media player does not keep a reference to the supplied equalizer so it is safe
for an application to release the equalizer reference any time after this method
returns.
@param p_equalizer: opaque equalizer handle, or NULL to disable the equalizer for this media player.
@return: zero on success, -1 on error.
@version: LibVLC 2.2.0 or later.
'''
return libvlc_media_player_set_equalizer(self, p_equalizer)
# LibVLC __version__ functions # # LibVLC __version__ functions #
@ -3279,6 +3399,20 @@ def libvlc_set_user_agent(p_instance, name, http):
None, Instance, ctypes.c_char_p, ctypes.c_char_p) None, Instance, ctypes.c_char_p, ctypes.c_char_p)
return f(p_instance, name, http) return f(p_instance, name, http)
def libvlc_set_app_id(p_instance, id, version, icon):
'''Sets some meta-information about the application.
See also L{libvlc_set_user_agent}().
@param p_instance: LibVLC instance.
@param id: Java-style application identifier, e.g. "com.acme.foobar".
@param version: application version numbers, e.g. "1.2.3".
@param icon: application icon name, e.g. "foobar".
@version: LibVLC 2.1.0 or later.
'''
f = _Cfunctions.get('libvlc_set_app_id', None) or \
_Cfunction('libvlc_set_app_id', ((1,), (1,), (1,), (1,),), None,
None, Instance, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p)
return f(p_instance, id, version, icon)
def libvlc_get_version(): def libvlc_get_version():
'''Retrieve libvlc version. '''Retrieve libvlc version.
Example: "1.1.0-git The Luggage". Example: "1.1.0-git The Luggage".
@ -3355,7 +3489,7 @@ def libvlc_event_type_name(event_type):
return f(event_type) return f(event_type)
def libvlc_log_get_context(ctx): def libvlc_log_get_context(ctx):
'''Gets debugging informations about a log message: the name of the VLC module '''Gets debugging information about a log message: the name of the VLC module
emitting the message and the message location within the source code. emitting the message and the message location within the source code.
The returned module name and file name will be NULL if unknown. The returned module name and file name will be NULL if unknown.
The returned line number will similarly be zero if unknown. The returned line number will similarly be zero if unknown.
@ -3369,9 +3503,9 @@ def libvlc_log_get_context(ctx):
return f(ctx) return f(ctx)
def libvlc_log_get_object(ctx, id): def libvlc_log_get_object(ctx, id):
'''Gets VLC object informations about a log message: the type name of the VLC '''Gets VLC object information about a log message: the type name of the VLC
object emitting the message, the object header if any and a temporaly-unique object emitting the message, the object header if any and a temporaly-unique
object identifier. These informations are mainly meant for B{manual} object identifier. This information is mainly meant for B{manual}
troubleshooting. troubleshooting.
The returned type name may be "generic" if unknown, but it cannot be NULL. The returned type name may be "generic" if unknown, but it cannot be NULL.
The returned header will be NULL if unset; in current versions, the header The returned header will be NULL if unset; in current versions, the header
@ -4814,6 +4948,17 @@ def libvlc_media_player_can_pause(p_mi):
ctypes.c_int, MediaPlayer) ctypes.c_int, MediaPlayer)
return f(p_mi) return f(p_mi)
def libvlc_media_player_program_scrambled(p_mi):
'''Check if the current program is scrambled.
@param p_mi: the media player.
@return: true if the current program is scrambled \libvlc_return_bool.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_media_player_program_scrambled', None) or \
_Cfunction('libvlc_media_player_program_scrambled', ((1,),), None,
ctypes.c_int, MediaPlayer)
return f(p_mi)
def libvlc_media_player_next_frame(p_mi): def libvlc_media_player_next_frame(p_mi):
'''Display the next frame (if supported). '''Display the next frame (if supported).
@param p_mi: the media player. @param p_mi: the media player.
@ -4834,6 +4979,18 @@ def libvlc_media_player_navigate(p_mi, navigate):
None, MediaPlayer, ctypes.c_uint) None, MediaPlayer, ctypes.c_uint)
return f(p_mi, navigate) return f(p_mi, navigate)
def libvlc_media_player_set_video_title_display(p_mi, position, timeout):
'''Set if, and how, the video title will be shown when media is played.
@param p_mi: the media player.
@param position: position at which to display the title, or libvlc_position_disable to prevent the title from being displayed.
@param timeout: title display timeout in milliseconds (ignored if libvlc_position_disable).
@version: libVLC 2.1.0 or later.
'''
f = _Cfunctions.get('libvlc_media_player_set_video_title_display', None) or \
_Cfunction('libvlc_media_player_set_video_title_display', ((1,), (1,), (1,),), None,
None, MediaPlayer, Position, ctypes.c_int)
return f(p_mi, position, timeout)
def libvlc_track_description_list_release(p_track_description): def libvlc_track_description_list_release(p_track_description):
'''Release (free) L{TrackDescription}. '''Release (free) L{TrackDescription}.
@param p_track_description: the structure to release. @param p_track_description: the structure to release.
@ -5335,7 +5492,7 @@ def libvlc_video_set_adjust_float(p_mi, option, value):
return f(p_mi, option, value) return f(p_mi, option, value)
def libvlc_audio_output_list_get(p_instance): def libvlc_audio_output_list_get(p_instance):
'''Gets the list of available audio outputs. '''Gets the list of available audio output modules.
@param p_instance: libvlc instance. @param p_instance: libvlc instance.
@return: list of available audio outputs. It must be freed it with In case of error, NULL is returned. @return: list of available audio outputs. It must be freed it with In case of error, NULL is returned.
''' '''
@ -5345,7 +5502,7 @@ def libvlc_audio_output_list_get(p_instance):
return f(p_instance) return f(p_instance)
def libvlc_audio_output_list_release(p_list): def libvlc_audio_output_list_release(p_list):
'''Frees the list of available audio outputs. '''Frees the list of available audio output modules.
@param p_list: list with audio outputs for release. @param p_list: list with audio outputs for release.
''' '''
f = _Cfunctions.get('libvlc_audio_output_list_release', None) or \ f = _Cfunctions.get('libvlc_audio_output_list_release', None) or \
@ -5354,7 +5511,7 @@ def libvlc_audio_output_list_release(p_list):
return f(p_list) return f(p_list)
def libvlc_audio_output_set(p_mi, psz_name): def libvlc_audio_output_set(p_mi, psz_name):
'''Sets the audio output. '''Selects an audio output module.
@note: Any change will take be effect only after playback is stopped and @note: Any change will take be effect only after playback is stopped and
restarted. Audio output cannot be changed while playing. restarted. Audio output cannot be changed while playing.
@param p_mi: media player. @param p_mi: media player.
@ -5366,8 +5523,26 @@ def libvlc_audio_output_set(p_mi, psz_name):
ctypes.c_int, MediaPlayer, ctypes.c_char_p) ctypes.c_int, MediaPlayer, ctypes.c_char_p)
return f(p_mi, psz_name) return f(p_mi, psz_name)
def libvlc_audio_output_device_enum(mp):
'''Gets a list of potential audio output devices,
See L{libvlc_audio_output_device_set}().
@note: Not all audio outputs support enumerating devices.
The audio output may be functional even if the list is empty (NULL).
@note: The list may not be exhaustive.
@warning: Some audio output devices in the list might not actually work in
some circumstances. By default, it is recommended to not specify any
explicit audio device.
@param mp: media player.
@return: A NULL-terminated linked list of potential audio output devices. It must be freed it with L{libvlc_audio_output_device_list_release}().
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_output_device_enum', None) or \
_Cfunction('libvlc_audio_output_device_enum', ((1,),), None,
ctypes.POINTER(AudioOutputDevice), MediaPlayer)
return f(mp)
def libvlc_audio_output_device_list_get(p_instance, aout): def libvlc_audio_output_device_list_get(p_instance, aout):
'''Gets a list of audio output devices for a given audio output. '''Gets a list of audio output devices for a given audio output module,
See L{libvlc_audio_output_device_set}(). See L{libvlc_audio_output_device_set}().
@note: Not all audio outputs support this. In particular, an empty (NULL) @note: Not all audio outputs support this. In particular, an empty (NULL)
list of devices does B{not} imply that the specified audio output does list of devices does B{not} imply that the specified audio output does
@ -5396,25 +5571,36 @@ def libvlc_audio_output_device_list_release(p_list):
None, ctypes.POINTER(AudioOutputDevice)) None, ctypes.POINTER(AudioOutputDevice))
return f(p_list) return f(p_list)
def libvlc_audio_output_device_set(p_mi, psz_audio_output, psz_device_id): def libvlc_audio_output_device_set(mp, module, device_id):
'''Configures an explicit audio output device for a given audio output plugin. '''Configures an explicit audio output device.
A list of possible devices can be obtained with If the module paramater is NULL, audio output will be moved to the device
specified by the device identifier string immediately. This is the
recommended usage.
A list of adequate potential device strings can be obtained with
L{libvlc_audio_output_device_enum}().
However passing NULL is supported in LibVLC version 2.2.0 and later only;
in earlier versions, this function would have no effects when the module
parameter was NULL.
If the module parameter is not NULL, the device parameter of the
corresponding audio output, if it exists, will be set to the specified
string. Note that some audio output modules do not have such a parameter
(notably MMDevice and PulseAudio).
A list of adequate potential device strings can be obtained with
L{libvlc_audio_output_device_list_get}(). L{libvlc_audio_output_device_list_get}().
@note: This function does not select the specified audio output plugin. @note: This function does not select the specified audio output plugin.
L{libvlc_audio_output_set}() is used for that purpose. L{libvlc_audio_output_set}() is used for that purpose.
@warning: The syntax for the device parameter depends on the audio output. @warning: The syntax for the device parameter depends on the audio output.
This is not portable. Only use this function if you know what you are doing. Some audio output modules require further parameters (e.g. a channels map
Some audio outputs do not support this function (e.g. PulseAudio, WASAPI). in the case of ALSA).
Some audio outputs require further parameters (e.g. ALSA: channels map). @param mp: media player.
@param p_mi: media player. @param module: If NULL, current audio output module. if non-NULL, name of audio output module.
@param psz_audio_output: - name of audio output, See L{AudioOutput}. @param device_id: device identifier string.
@param psz_device_id: device. @return: Nothing. Errors are ignored (this is a design bug).
@return: Nothing. Errors are ignored.
''' '''
f = _Cfunctions.get('libvlc_audio_output_device_set', None) or \ f = _Cfunctions.get('libvlc_audio_output_device_set', None) or \
_Cfunction('libvlc_audio_output_device_set', ((1,), (1,), (1,),), None, _Cfunction('libvlc_audio_output_device_set', ((1,), (1,), (1,),), None,
None, MediaPlayer, ctypes.c_char_p, ctypes.c_char_p) None, MediaPlayer, ctypes.c_char_p, ctypes.c_char_p)
return f(p_mi, psz_audio_output, psz_device_id) return f(mp, module, device_id)
def libvlc_audio_toggle_mute(p_mi): def libvlc_audio_toggle_mute(p_mi):
'''Toggle mute status. '''Toggle mute status.
@ -5551,6 +5737,175 @@ def libvlc_audio_set_delay(p_mi, i_delay):
ctypes.c_int, MediaPlayer, ctypes.c_int64) ctypes.c_int, MediaPlayer, ctypes.c_int64)
return f(p_mi, i_delay) return f(p_mi, i_delay)
def libvlc_audio_equalizer_get_preset_count():
'''Get the number of equalizer presets.
@return: number of presets.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_get_preset_count', None) or \
_Cfunction('libvlc_audio_equalizer_get_preset_count', (), None,
ctypes.c_uint)
return f()
def libvlc_audio_equalizer_get_preset_name(u_index):
'''Get the name of a particular equalizer preset.
This name can be used, for example, to prepare a preset label or menu in a user
interface.
@param u_index: index of the preset, counting from zero.
@return: preset name, or NULL if there is no such preset.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_get_preset_name', None) or \
_Cfunction('libvlc_audio_equalizer_get_preset_name', ((1,),), None,
ctypes.c_char_p, ctypes.c_uint)
return f(u_index)
def libvlc_audio_equalizer_get_band_count():
'''Get the number of distinct frequency bands for an equalizer.
@return: number of frequency bands.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_get_band_count', None) or \
_Cfunction('libvlc_audio_equalizer_get_band_count', (), None,
ctypes.c_uint)
return f()
def libvlc_audio_equalizer_get_band_frequency(u_index):
'''Get a particular equalizer band frequency.
This value can be used, for example, to create a label for an equalizer band control
in a user interface.
@param u_index: index of the band, counting from zero.
@return: equalizer band frequency (Hz), or -1 if there is no such band.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_get_band_frequency', None) or \
_Cfunction('libvlc_audio_equalizer_get_band_frequency', ((1,),), None,
ctypes.c_float, ctypes.c_uint)
return f(u_index)
def libvlc_audio_equalizer_new():
'''Create a new default equalizer, with all frequency values zeroed.
The new equalizer can subsequently be applied to a media player by invoking
L{libvlc_media_player_set_equalizer}().
The returned handle should be freed via L{libvlc_audio_equalizer_release}() when
it is no longer needed.
@return: opaque equalizer handle, or NULL on error.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_new', None) or \
_Cfunction('libvlc_audio_equalizer_new', (), None,
ctypes.c_void_p)
return f()
def libvlc_audio_equalizer_new_from_preset(u_index):
'''Create a new equalizer, with initial frequency values copied from an existing
preset.
The new equalizer can subsequently be applied to a media player by invoking
L{libvlc_media_player_set_equalizer}().
The returned handle should be freed via L{libvlc_audio_equalizer_release}() when
it is no longer needed.
@param u_index: index of the preset, counting from zero.
@return: opaque equalizer handle, or NULL on error.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_new_from_preset', None) or \
_Cfunction('libvlc_audio_equalizer_new_from_preset', ((1,),), None,
ctypes.c_void_p, ctypes.c_uint)
return f(u_index)
def libvlc_audio_equalizer_release(p_equalizer):
'''Release a previously created equalizer instance.
The equalizer was previously created by using L{libvlc_audio_equalizer_new}() or
L{libvlc_audio_equalizer_new_from_preset}().
It is safe to invoke this method with a NULL p_equalizer parameter for no effect.
@param p_equalizer: opaque equalizer handle, or NULL.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_release', None) or \
_Cfunction('libvlc_audio_equalizer_release', ((1,),), None,
None, ctypes.c_void_p)
return f(p_equalizer)
def libvlc_audio_equalizer_set_preamp(p_equalizer, f_preamp):
'''Set a new pre-amplification value for an equalizer.
The new equalizer settings are subsequently applied to a media player by invoking
L{libvlc_media_player_set_equalizer}().
The supplied amplification value will be clamped to the -20.0 to +20.0 range.
@param p_equalizer: valid equalizer handle, must not be NULL.
@param f_preamp: preamp value (-20.0 to 20.0 Hz).
@return: zero on success, -1 on error.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_set_preamp', None) or \
_Cfunction('libvlc_audio_equalizer_set_preamp', ((1,), (1,),), None,
ctypes.c_int, ctypes.c_void_p, ctypes.c_float)
return f(p_equalizer, f_preamp)
def libvlc_audio_equalizer_get_preamp(p_equalizer):
'''Get the current pre-amplification value from an equalizer.
@param p_equalizer: valid equalizer handle, must not be NULL.
@return: preamp value (Hz).
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_get_preamp', None) or \
_Cfunction('libvlc_audio_equalizer_get_preamp', ((1,),), None,
ctypes.c_float, ctypes.c_void_p)
return f(p_equalizer)
def libvlc_audio_equalizer_set_amp_at_index(p_equalizer, f_amp, u_band):
'''Set a new amplification value for a particular equalizer frequency band.
The new equalizer settings are subsequently applied to a media player by invoking
L{libvlc_media_player_set_equalizer}().
The supplied amplification value will be clamped to the -20.0 to +20.0 range.
@param p_equalizer: valid equalizer handle, must not be NULL.
@param f_amp: amplification value (-20.0 to 20.0 Hz).
@param u_band: index, counting from zero, of the frequency band to set.
@return: zero on success, -1 on error.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_set_amp_at_index', None) or \
_Cfunction('libvlc_audio_equalizer_set_amp_at_index', ((1,), (1,), (1,),), None,
ctypes.c_int, ctypes.c_void_p, ctypes.c_float, ctypes.c_uint)
return f(p_equalizer, f_amp, u_band)
def libvlc_audio_equalizer_get_amp_at_index(p_equalizer, u_band):
'''Get the amplification value for a particular equalizer frequency band.
@param p_equalizer: valid equalizer handle, must not be NULL.
@param u_band: index, counting from zero, of the frequency band to get.
@return: amplification value (Hz); NaN if there is no such frequency band.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_audio_equalizer_get_amp_at_index', None) or \
_Cfunction('libvlc_audio_equalizer_get_amp_at_index', ((1,), (1,),), None,
ctypes.c_float, ctypes.c_void_p, ctypes.c_uint)
return f(p_equalizer, u_band)
def libvlc_media_player_set_equalizer(p_mi, p_equalizer):
'''Apply new equalizer settings to a media player.
The equalizer is first created by invoking L{libvlc_audio_equalizer_new}() or
L{libvlc_audio_equalizer_new_from_preset}().
It is possible to apply new equalizer settings to a media player whether the media
player is currently playing media or not.
Invoking this method will immediately apply the new equalizer settings to the audio
output of the currently playing media if there is any.
If there is no currently playing media, the new equalizer settings will be applied
later if and when new media is played.
Equalizer settings will automatically be applied to subsequently played media.
To disable the equalizer for a media player invoke this method passing NULL for the
p_equalizer parameter.
The media player does not keep a reference to the supplied equalizer so it is safe
for an application to release the equalizer reference any time after this method
returns.
@param p_mi: opaque media player handle.
@param p_equalizer: opaque equalizer handle, or NULL to disable the equalizer for this media player.
@return: zero on success, -1 on error.
@version: LibVLC 2.2.0 or later.
'''
f = _Cfunctions.get('libvlc_media_player_set_equalizer', None) or \
_Cfunction('libvlc_media_player_set_equalizer', ((1,), (1,),), None,
ctypes.c_int, MediaPlayer, ctypes.c_void_p)
return f(p_mi, p_equalizer)
def libvlc_vlm_release(p_instance): def libvlc_vlm_release(p_instance):
'''Release the vlm instance related to the given L{Instance}. '''Release the vlm instance related to the given L{Instance}.
@param p_instance: the instance. @param p_instance: the instance.
@ -5863,7 +6218,18 @@ def libvlc_vlm_get_event_manager(p_instance):
# libvlc_printerr # libvlc_printerr
# libvlc_set_exit_handler # libvlc_set_exit_handler
# 17 function(s) not wrapped as methods: # 28 function(s) not wrapped as methods:
# libvlc_audio_equalizer_get_amp_at_index
# libvlc_audio_equalizer_get_band_count
# libvlc_audio_equalizer_get_band_frequency
# libvlc_audio_equalizer_get_preamp
# libvlc_audio_equalizer_get_preset_count
# libvlc_audio_equalizer_get_preset_name
# libvlc_audio_equalizer_new
# libvlc_audio_equalizer_new_from_preset
# libvlc_audio_equalizer_release
# libvlc_audio_equalizer_set_amp_at_index
# libvlc_audio_equalizer_set_preamp
# 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

View File

@ -18,11 +18,11 @@
# Software Foundation; version 2 of the License. # # Software Foundation; version 2 of the License. #
# # # #
# This program is distributed in the hope that it will be useful, but WITHOUT # # This program is distributed in the hope that it will be useful, but WITHOUT #
# AN_y WARRANT_y; without even the implied warranty of MERCHANTABILIT_y or # # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. # # more details. #
# # # #
# _you should have received a copy of the GNU General Public License along # # You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
@ -179,7 +179,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard, RegistryProperties):
if self.page(self.currentId()) == self.background_page and \ if self.page(self.currentId()) == self.background_page and \
self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename): self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename):
QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'), QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),
translate('OpenLP.ThemeWizard', '_you have not selected a ' translate('OpenLP.ThemeWizard', 'You have not selected a '
'background image. Please select one before continuing.')) 'background image. Please select one before continuing.'))
return False return False
else: else:

View File

@ -71,8 +71,7 @@ class LanguageManager(object):
""" """
Find all available language files in this OpenLP install Find all available language files in this OpenLP install
""" """
log.debug('Translation files: %s', AppLocation.get_directory( log.debug('Translation files: %s', AppLocation.get_directory(AppLocation.LanguageDir))
AppLocation.LanguageDir))
trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir)) trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir))
file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name) file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt_". # Remove qm files from the list which start with "qt_".

View File

@ -149,7 +149,7 @@ class CSVBible(BibleDB):
book_ptr = book.name book_ptr = book.name
self.wizard.increment_progress_bar( self.wizard.increment_progress_bar(
translate('BiblesPlugin.CSVBible', translate('BiblesPlugin.CSVBible',
'Importing verses from %s... Importing verses from <book name>...') % book.name) 'Importing verses from %s...' % book.name, 'Importing verses from <book name>...'))
self.session.commit() self.session.commit()
try: try:
verse_text = str(line[3], details['encoding']) verse_text = str(line[3], details['encoding'])

View File

@ -225,7 +225,7 @@ class BGExtract(RegistryProperties):
url_book_name = urllib.parse.quote(book_name.encode("utf-8")) url_book_name = urllib.parse.quote(book_name.encode("utf-8"))
url_params = 'search=%s+%s&version=%s' % (url_book_name, chapter, version) url_params = 'search=%s+%s&version=%s' % (url_book_name, chapter, version)
soup = get_soup_for_bible_ref( soup = get_soup_for_bible_ref(
'http://www.biblegateway.com/passage/?%s' % url_params, 'http://legacy.biblegateway.com/passage/?%s' % url_params,
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='') pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='')
if not soup: if not soup:
return None return None
@ -252,7 +252,7 @@ class BGExtract(RegistryProperties):
""" """
log.debug('BGExtract.get_books_from_http("%s")', version) log.debug('BGExtract.get_books_from_http("%s")', version)
url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '%s' % version}) url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '%s' % version})
reference_url = 'http://www.biblegateway.com/versions/?%s#books' % url_params reference_url = 'http://legacy.biblegateway.com/versions/?%s#books' % url_params
page = get_web_page(reference_url) page = get_web_page(reference_url)
if not page: if not page:
send_error_message('download') send_error_message('download')

View File

@ -126,8 +126,8 @@ class PdfController(PresentationController):
if os.name == 'nt': if os.name == 'nt':
# for windows we only accept mudraw.exe in the base folder # for windows we only accept mudraw.exe in the base folder
application_path = AppLocation.get_directory(AppLocation.AppDir) application_path = AppLocation.get_directory(AppLocation.AppDir)
if os.path.isfile(application_path + '/../mudraw.exe'): if os.path.isfile(os.path.join(application_path, 'mudraw.exe')):
self.mudrawbin = application_path + '/../mudraw.exe' self.mudrawbin = os.path.join(application_path, 'mudraw.exe')
else: else:
DEVNULL = open(os.devnull, 'wb') DEVNULL = open(os.devnull, 'wb')
# First try to find mupdf # First try to find mupdf
@ -145,8 +145,8 @@ class PdfController(PresentationController):
# Last option: check if mudraw is placed in OpenLP base folder # Last option: check if mudraw is placed in OpenLP base folder
if not self.mudrawbin and not self.gsbin: if not self.mudrawbin and not self.gsbin:
application_path = AppLocation.get_directory(AppLocation.AppDir) application_path = AppLocation.get_directory(AppLocation.AppDir)
if os.path.isfile(application_path + '/../mudraw'): if os.path.isfile(os.path.join(application_path, 'mudraw')):
self.mudrawbin = application_path + '/../mudraw' self.mudrawbin = os.path.join(application_path, 'mudraw')
if self.mudrawbin: if self.mudrawbin:
self.also_supports = ['xps'] self.also_supports = ['xps']
return True return True

View File

@ -40,6 +40,8 @@ if os.name == 'nt':
import pywintypes import pywintypes
from openlp.core.lib import ScreenList from openlp.core.lib import ScreenList
from openlp.core.lib.ui import UiStrings, critical_error_message_box, translate
from openlp.core.common import trace_error_handler
from .presentationcontroller import PresentationController, PresentationDocument from .presentationcontroller import PresentationController, PresentationDocument
@ -99,7 +101,7 @@ class PowerpointController(PresentationController):
if self.process.Presentations.Count > 0: if self.process.Presentations.Count > 0:
return return
self.process.Quit() self.process.Quit()
except pywintypes.com_error: except (AttributeError, pywintypes.com_error):
pass pass
self.process = None self.process = None
@ -126,16 +128,24 @@ class PowerpointDocument(PresentationDocument):
earlier. earlier.
""" """
log.debug('load_presentation') log.debug('load_presentation')
try:
if not self.controller.process or not self.controller.process.Visible: if not self.controller.process or not self.controller.process.Visible:
self.controller.start_process() self.controller.start_process()
try:
self.controller.process.Presentations.Open(self.file_path, False, False, True) self.controller.process.Presentations.Open(self.file_path, False, False, True)
except pywintypes.com_error:
log.debug('PPT open failed')
return False
self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count) self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count)
self.create_thumbnails() self.create_thumbnails()
# Powerpoint 2013 pops up when loading a file, so we minimize it again
if self.presentation.Application.Version == u'15.0':
try:
self.presentation.Application.WindowState = 2
except:
log.error('Failed to minimize main powerpoint window')
trace_error_handler(log)
return True return True
except pywintypes.com_error:
log.error('PPT open failed')
trace_error_handler(log)
return False
def create_thumbnails(self): def create_thumbnails(self):
""" """
@ -206,6 +216,7 @@ class PowerpointDocument(PresentationDocument):
Unblanks (restores) the presentation. Unblanks (restores) the presentation.
""" """
log.debug('unblank_screen') log.debug('unblank_screen')
try:
self.presentation.SlideShowSettings.Run() self.presentation.SlideShowSettings.Run()
self.presentation.SlideShowWindow.View.State = 1 self.presentation.SlideShowWindow.View.State = 1
self.presentation.SlideShowWindow.Activate() self.presentation.SlideShowWindow.Activate()
@ -216,13 +227,22 @@ class PowerpointDocument(PresentationDocument):
self.presentation.SlideShowWindow.View.GotoSlide(slide) self.presentation.SlideShowWindow.View.GotoSlide(slide)
if click: if click:
self.presentation.SlideShowWindow.View.GotoClick(click) self.presentation.SlideShowWindow.View.GotoClick(click)
except pywintypes.com_error:
log.error('COM error while in unblank_screen')
trace_error_handler(log)
self.show_error_msg()
def blank_screen(self): def blank_screen(self):
""" """
Blanks the screen. Blanks the screen.
""" """
log.debug('blank_screen') log.debug('blank_screen')
try:
self.presentation.SlideShowWindow.View.State = 3 self.presentation.SlideShowWindow.View.State = 3
except pywintypes.com_error:
log.error('COM error while in blank_screen')
trace_error_handler(log)
self.show_error_msg()
def is_blank(self): def is_blank(self):
""" """
@ -230,7 +250,12 @@ class PowerpointDocument(PresentationDocument):
""" """
log.debug('is_blank') log.debug('is_blank')
if self.is_active(): if self.is_active():
try:
return self.presentation.SlideShowWindow.View.State == 3 return self.presentation.SlideShowWindow.View.State == 3
except pywintypes.com_error:
log.error('COM error while in is_blank')
trace_error_handler(log)
self.show_error_msg()
else: else:
return False return False
@ -239,7 +264,12 @@ class PowerpointDocument(PresentationDocument):
Stops the current presentation and hides the output. Stops the current presentation and hides the output.
""" """
log.debug('stop_presentation') log.debug('stop_presentation')
try:
self.presentation.SlideShowWindow.View.Exit() self.presentation.SlideShowWindow.View.Exit()
except pywintypes.com_error:
log.error('COM error while in stop_presentation')
trace_error_handler(log)
self.show_error_msg()
if os.name == 'nt': if os.name == 'nt':
def start_presentation(self): def start_presentation(self):
@ -259,24 +289,49 @@ class PowerpointDocument(PresentationDocument):
ppt_window = self.presentation.SlideShowSettings.Run() ppt_window = self.presentation.SlideShowSettings.Run()
if not ppt_window: if not ppt_window:
return return
try:
ppt_window.Top = size.y() * 72 / dpi ppt_window.Top = size.y() * 72 / dpi
ppt_window.Height = size.height() * 72 / dpi ppt_window.Height = size.height() * 72 / dpi
ppt_window.Left = size.x() * 72 / dpi ppt_window.Left = size.x() * 72 / dpi
ppt_window.Width = size.width() * 72 / dpi ppt_window.Width = size.width() * 72 / dpi
except AttributeError as e:
log.error('AttributeError while in start_presentation')
log.error(e)
# Powerpoint 2013 pops up when starting a file, so we minimize it again
if self.presentation.Application.Version == u'15.0':
try:
self.presentation.Application.WindowState = 2
except:
log.error('Failed to minimize main powerpoint window')
trace_error_handler(log)
def get_slide_number(self): def get_slide_number(self):
""" """
Returns the current slide number. Returns the current slide number.
""" """
log.debug('get_slide_number') log.debug('get_slide_number')
return self.presentation.SlideShowWindow.View.CurrentShowPosition ret = 0
try:
ret = self.presentation.SlideShowWindow.View.CurrentShowPosition
except pywintypes.com_error:
log.error('COM error while in get_slide_number')
trace_error_handler(log)
self.show_error_msg()
return ret
def get_slide_count(self): def get_slide_count(self):
""" """
Returns total number of slides. Returns total number of slides.
""" """
log.debug('get_slide_count') log.debug('get_slide_count')
return self.presentation.Slides.Count ret = 0
try:
ret = self.presentation.Slides.Count
except pywintypes.com_error:
log.error('COM error while in get_slide_count')
trace_error_handler(log)
self.show_error_msg()
return ret
def goto_slide(self, slide_no): def goto_slide(self, slide_no):
""" """
@ -285,14 +340,25 @@ class PowerpointDocument(PresentationDocument):
:param slide_no: The slide the text is required for, starting at 1 :param slide_no: The slide the text is required for, starting at 1
""" """
log.debug('goto_slide') log.debug('goto_slide')
try:
self.presentation.SlideShowWindow.View.GotoSlide(slide_no) self.presentation.SlideShowWindow.View.GotoSlide(slide_no)
except pywintypes.com_error:
log.error('COM error while in goto_slide')
trace_error_handler(log)
self.show_error_msg()
def next_step(self): def next_step(self):
""" """
Triggers the next effect of slide on the running presentation. Triggers the next effect of slide on the running presentation.
""" """
log.debug('next_step') log.debug('next_step')
try:
self.presentation.SlideShowWindow.View.Next() self.presentation.SlideShowWindow.View.Next()
except pywintypes.com_error:
log.error('COM error while in next_step')
trace_error_handler(log)
self.show_error_msg()
return
if self.get_slide_number() > self.get_slide_count(): if self.get_slide_number() > self.get_slide_count():
self.previous_step() self.previous_step()
@ -301,7 +367,12 @@ class PowerpointDocument(PresentationDocument):
Triggers the previous slide on the running presentation. Triggers the previous slide on the running presentation.
""" """
log.debug('previous_step') log.debug('previous_step')
try:
self.presentation.SlideShowWindow.View.Previous() self.presentation.SlideShowWindow.View.Previous()
except pywintypes.com_error:
log.error('COM error while in previous_step')
trace_error_handler(log)
self.show_error_msg()
def get_slide_text(self, slide_no): def get_slide_text(self, slide_no):
""" """
@ -319,6 +390,16 @@ class PowerpointDocument(PresentationDocument):
""" """
return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes) return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes)
def show_error_msg(self):
"""
Stop presentation and display an error message.
"""
self.stop_presentation()
critical_error_message_box(UiStrings().Error, translate('PresentationPlugin.PowerpointDocument',
'An error occurred in the Powerpoint integration '
'and the presentation will be stopped. '
'Restart the presentation if you wish to present it.'))
def _get_text_from_shapes(shapes): def _get_text_from_shapes(shapes):
""" """

View File

@ -44,7 +44,7 @@ from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_me
from openlp.plugins.songs.lib import VerseType, clean_song from openlp.plugins.songs.lib import VerseType, clean_song
from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorType, Topic, MediaFile from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorType, Topic, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
from openlp.plugins.songs.lib.xml import SongXML from openlp.plugins.songs.lib.openlyricsxml import SongXML
from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog
from openlp.plugins.songs.forms.editverseform import EditVerseForm from openlp.plugins.songs.forms.editverseform import EditVerseForm
from openlp.plugins.songs.forms.mediafilesform import MediaFilesForm from openlp.plugins.songs.forms.mediafilesform import MediaFilesForm

View File

@ -33,7 +33,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon from openlp.core.lib import build_icon
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.xml import SongXML from openlp.plugins.songs.lib.openlyricsxml import SongXML
class SongReviewWidget(QtGui.QWidget): class SongReviewWidget(QtGui.QWidget):

View File

@ -74,10 +74,11 @@ class AuthorType(object):
WordsAndMusic = 'words+music' WordsAndMusic = 'words+music'
Translation = 'translation' Translation = 'translation'
Types = { Types = {
Words: translate('OpenLP.Ui', 'Words'), Words: translate('SongsPlugin.AuthorType', 'Words', 'Author who wrote the lyrics of a song'),
Music: translate('OpenLP.Ui', 'Music'), Music: translate('SongsPlugin.AuthorType', 'Music', 'Author who wrote the music of a song'),
WordsAndMusic: translate('OpenLP.Ui', 'Words and Music'), WordsAndMusic: translate('SongsPlugin.AuthorType', 'Words and Music',
Translation: translate('OpenLP.Ui', 'Translation') 'Author who wrote both lyrics and music of a song'),
Translation: translate('SongsPlugin.AuthorType', 'Translation', 'Author who translated the song')
} }

View File

@ -34,21 +34,23 @@ import logging
from openlp.core.common import translate, UiStrings from openlp.core.common import translate, UiStrings
from openlp.core.ui.wizard import WizardStrings from openlp.core.ui.wizard import WizardStrings
from .opensongimport import OpenSongImport from .importers.opensong import OpenSongImport
from .easyslidesimport import EasySlidesImport from .importers.easyslides import EasySlidesImport
from .olpimport import OpenLPSongImport from .importers.openlp import OpenLPSongImport
from .openlyricsimport import OpenLyricsImport from .importers.openlyrics import OpenLyricsImport
from .wowimport import WowImport from .importers.wordsofworship import WordsOfWorshipImport
from .cclifileimport import CCLIFileImport from .importers.cclifile import CCLIFileImport
from .dreambeamimport import DreamBeamImport from .importers.dreambeam import DreamBeamImport
from .powersongimport import PowerSongImport from .importers.powersong import PowerSongImport
from .ewimport import EasyWorshipSongImport from .importers.easyworship import EasyWorshipSongImport
from .songbeamerimport import SongBeamerImport from .importers.songbeamer import SongBeamerImport
from .songshowplusimport import SongShowPlusImport from .importers.songshowplus import SongShowPlusImport
from .songproimport import SongProImport from .importers.songpro import SongProImport
from .sundayplusimport import SundayPlusImport from .importers.sundayplus import SundayPlusImport
from .foilpresenterimport import FoilPresenterImport from .importers.foilpresenter import FoilPresenterImport
from .zionworximport import ZionWorxImport from .importers.zionworx import ZionWorxImport
from .importers.propresenter import ProPresenterImport
from .importers.worshipassistant import WorshipAssistantImport
# Imports that might fail # Imports that might fail
@ -56,13 +58,13 @@ log = logging.getLogger(__name__)
try: try:
from .sofimport import SofImport from .importers.songsoffellowship import SongsOfFellowshipImport
HAS_SOF = True HAS_SOF = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'SofImport') log.exception('Error importing %s', 'SongsOfFellowshipImport')
HAS_SOF = False HAS_SOF = False
try: try:
from .oooimport import OooImport from .importers.openoffice import OpenOfficeImport
HAS_OOO = True HAS_OOO = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'OooImport') log.exception('Error importing %s', 'OooImport')
@ -70,14 +72,14 @@ except ImportError:
HAS_MEDIASHOUT = False HAS_MEDIASHOUT = False
if os.name == 'nt': if os.name == 'nt':
try: try:
from .mediashoutimport import MediaShoutImport from .importers.mediashout import MediaShoutImport
HAS_MEDIASHOUT = True HAS_MEDIASHOUT = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'MediaShoutImport') log.exception('Error importing %s', 'MediaShoutImport')
HAS_WORSHIPCENTERPRO = False HAS_WORSHIPCENTERPRO = False
if os.name == 'nt': if os.name == 'nt':
try: try:
from .worshipcenterproimport import WorshipCenterProImport from .importers.worshipcenterpro import WorshipCenterProImport
HAS_WORSHIPCENTERPRO = True HAS_WORSHIPCENTERPRO = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'WorshipCenterProImport') log.exception('Error importing %s', 'WorshipCenterProImport')
@ -107,7 +109,7 @@ class SongFormat(object):
Name of the format, e.g. ``'OpenLyrics'`` Name of the format, e.g. ``'OpenLyrics'``
``'prefix'`` ``'prefix'``
Prefix for Qt objects. Use mixedCase, e.g. ``'open_lyrics'`` Prefix for Qt objects. Use mixedCase, e.g. ``'openLyrics'``
See ``SongImportForm.add_file_select_item()`` See ``SongImportForm.add_file_select_item()``
Optional attributes for each song format: Optional attributes for each song format:
@ -159,14 +161,16 @@ class SongFormat(object):
MediaShout = 9 MediaShout = 9
OpenSong = 10 OpenSong = 10
PowerSong = 11 PowerSong = 11
SongBeamer = 12 ProPresenter = 12
SongPro = 13 SongBeamer = 13
SongShowPlus = 14 SongPro = 14
SongsOfFellowship = 15 SongShowPlus = 15
SundayPlus = 16 SongsOfFellowship = 16
WordsOfWorship = 17 SundayPlus = 17
WorshipCenterPro = 18 WordsOfWorship = 18
ZionWorx = 19 WorshipAssistant = 19
WorshipCenterPro = 20
ZionWorx = 21
# Set optional attribute defaults # Set optional attribute defaults
__defaults__ = { __defaults__ = {
@ -186,7 +190,7 @@ class SongFormat(object):
OpenLyrics: { OpenLyrics: {
'class': OpenLyricsImport, 'class': OpenLyricsImport,
'name': 'OpenLyrics', 'name': 'OpenLyrics',
'prefix': 'open_lyrics', 'prefix': 'openLyrics',
'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'), 'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2.0 Exported Song') 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2.0 Exported Song')
}, },
@ -270,6 +274,12 @@ class SongFormat(object):
'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', 'You need to specify a valid PowerSong 1.0 ' 'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', 'You need to specify a valid PowerSong 1.0 '
'database folder.') 'database folder.')
}, },
ProPresenter: {
'class': ProPresenterImport,
'name': 'ProPresenter',
'prefix': 'proPresenter',
'filter': '%s (*.pro4)' % translate('SongsPlugin.ImportWizardForm', 'ProPresenter Song Files')
},
SongBeamer: { SongBeamer: {
'class': SongBeamerImport, 'class': SongBeamerImport,
'name': 'SongBeamer', 'name': 'SongBeamer',
@ -308,11 +318,21 @@ class SongFormat(object):
'filter': '%s (*.ptf)' % translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files') 'filter': '%s (*.ptf)' % translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files')
}, },
WordsOfWorship: { WordsOfWorship: {
'class': WowImport, 'class': WordsOfWorshipImport,
'name': 'Words of Worship', 'name': 'Words of Worship',
'prefix': 'wordsOfWorship', 'prefix': 'wordsOfWorship',
'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') 'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files')
}, },
WorshipAssistant: {
'class': WorshipAssistantImport,
'name': 'Worship Assistant 0',
'prefix': 'worshipAssistant',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.csv)' % translate('SongsPlugin.ImportWizardForm', 'Worship Assistant Files'),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'Worship Assistant (CSV)'),
'descriptionText': translate('SongsPlugin.ImportWizardForm',
'In Worship Assistant, export your Database to a CSV file.')
},
WorshipCenterPro: { WorshipCenterPro: {
'name': 'WorshipCenter Pro', 'name': 'WorshipCenter Pro',
'prefix': 'worshipCenterPro', 'prefix': 'worshipCenterPro',
@ -355,22 +375,24 @@ class SongFormat(object):
SongFormat.MediaShout, SongFormat.MediaShout,
SongFormat.OpenSong, SongFormat.OpenSong,
SongFormat.PowerSong, SongFormat.PowerSong,
SongFormat.ProPresenter,
SongFormat.SongBeamer, SongFormat.SongBeamer,
SongFormat.SongPro, SongFormat.SongPro,
SongFormat.SongShowPlus, SongFormat.SongShowPlus,
SongFormat.SongsOfFellowship, SongFormat.SongsOfFellowship,
SongFormat.SundayPlus, SongFormat.SundayPlus,
SongFormat.WordsOfWorship, SongFormat.WordsOfWorship,
SongFormat.WorshipAssistant,
SongFormat.WorshipCenterPro, SongFormat.WorshipCenterPro,
SongFormat.ZionWorx SongFormat.ZionWorx
] ]
@staticmethod @staticmethod
def get(format, *attributes): def get(song_format, *attributes):
""" """
Return requested song format attribute(s). Return requested song format attribute(s).
:param format: A song format from SongFormat. :param song_format: A song format from SongFormat.
:param attributes: Zero or more song format attributes from SongFormat. :param attributes: Zero or more song format attributes from SongFormat.
Return type depends on number of supplied attributes: Return type depends on number of supplied attributes:
@ -380,31 +402,31 @@ class SongFormat(object):
:>1: Return tuple of requested attribute values. :>1: Return tuple of requested attribute values.
""" """
if not attributes: if not attributes:
return SongFormat.__attributes__.get(format) return SongFormat.__attributes__.get(song_format)
elif len(attributes) == 1: elif len(attributes) == 1:
default = SongFormat.__defaults__.get(attributes[0]) default = SongFormat.__defaults__.get(attributes[0])
return SongFormat.__attributes__[format].get(attributes[0], default) return SongFormat.__attributes__[song_format].get(attributes[0], default)
else: else:
values = [] values = []
for attr in attributes: for attr in attributes:
default = SongFormat.__defaults__.get(attr) default = SongFormat.__defaults__.get(attr)
values.append(SongFormat.__attributes__[format].get(attr, default)) values.append(SongFormat.__attributes__[song_format].get(attr, default))
return tuple(values) return tuple(values)
@staticmethod @staticmethod
def set(format, attribute, value): def set(song_format, attribute, value):
""" """
Set specified song format attribute to the supplied value. Set specified song format attribute to the supplied value.
""" """
SongFormat.__attributes__[format][attribute] = value SongFormat.__attributes__[song_format][attribute] = value
SongFormat.set(SongFormat.SongsOfFellowship, 'availability', HAS_SOF) SongFormat.set(SongFormat.SongsOfFellowship, 'availability', HAS_SOF)
if HAS_SOF: if HAS_SOF:
SongFormat.set(SongFormat.SongsOfFellowship, 'class', SofImport) SongFormat.set(SongFormat.SongsOfFellowship, 'class', SongsOfFellowshipImport)
SongFormat.set(SongFormat.Generic, 'availability', HAS_OOO) SongFormat.set(SongFormat.Generic, 'availability', HAS_OOO)
if HAS_OOO: if HAS_OOO:
SongFormat.set(SongFormat.Generic, 'class', OooImport) SongFormat.set(SongFormat.Generic, 'class', OpenOfficeImport)
SongFormat.set(SongFormat.MediaShout, 'availability', HAS_MEDIASHOUT) SongFormat.set(SongFormat.MediaShout, 'availability', HAS_MEDIASHOUT)
if HAS_MEDIASHOUT: if HAS_MEDIASHOUT:
SongFormat.set(SongFormat.MediaShout, 'class', MediaShoutImport) SongFormat.set(SongFormat.MediaShout, 'class', MediaShoutImport)

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.plugins.songs.lib.import` module contains importers for the Songs plugin.
"""

View File

@ -63,9 +63,8 @@ class CCLIFileImport(SongImport):
for filename in self.import_source: for filename in self.import_source:
filename = str(filename) filename = str(filename)
log.debug('Importing CCLI File: %s', filename) log.debug('Importing CCLI File: %s', filename)
lines = []
if os.path.isfile(filename): if os.path.isfile(filename):
detect_file = open(filename, 'r') detect_file = open(filename, 'rb')
detect_content = detect_file.read(2048) detect_content = detect_file.read(2048)
try: try:
str(detect_content, 'utf-8') str(detect_content, 'utf-8')
@ -250,7 +249,7 @@ class CCLIFileImport(SongImport):
# e.g. For use solely with the SongSelect Terms of Use. # e.g. For use solely with the SongSelect Terms of Use.
All rights Reserved. www.ccli.com All rights Reserved. www.ccli.com
CCLI Licence number of user CCLI Licence number of user
# e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14 # e.g. CCLI-Liedlizenznummer: 14 / CCLI License No. 14
""" """
log.debug('TXT file text: %s', text_list) log.debug('TXT file text: %s', text_list)

View File

@ -27,15 +27,14 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`dreambeamimport` module provides the functionality for importing The :mod:`dreambeam` module provides the functionality for importing DreamBeam songs into the OpenLP database.
DreamBeam songs into the OpenLP database.
""" """
import logging import logging
from lxml import etree, objectify from lxml import etree, objectify
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -33,7 +33,7 @@ import re
from lxml import etree, objectify from lxml import etree, objectify
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -27,8 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`ewimport` module provides the functionality for importing The :mod:`easyworship` module provides the functionality for importing EasyWorship song databases into OpenLP.
EasyWorship song databases into the current installation database.
""" """
import os import os
@ -200,11 +199,20 @@ class EasyWorshipSongImport(SongImport):
Import the songs from the database Import the songs from the database
""" """
# Open the DB and MB files if they exist # Open the DB and MB files if they exist
import_source_mb = self.import_source.replace('.DB', '.MB') import_source_mb = self.import_source.replace('.DB', '.MB').replace('.db', '.mb')
if not os.path.isfile(self.import_source) or not os.path.isfile(import_source_mb): if not os.path.isfile(self.import_source):
self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
'This file does not exist.'))
return
if not os.path.isfile(import_source_mb):
self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
'Could not find the "Songs.MB" file. It must be in the same '
'folder as the "Songs.DB" file.'))
return return
db_size = os.path.getsize(self.import_source) db_size = os.path.getsize(self.import_source)
if db_size < 0x800: if db_size < 0x800:
self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
'This file is not a valid EasyWorship database.'))
return return
db_file = open(self.import_source, 'rb') db_file = open(self.import_source, 'rb')
self.memo_file = open(import_source_mb, 'rb') self.memo_file = open(import_source_mb, 'rb')
@ -213,6 +221,8 @@ class EasyWorshipSongImport(SongImport):
if header_size != 0x800 or block_size < 1 or block_size > 4: if header_size != 0x800 or block_size < 1 or block_size > 4:
db_file.close() db_file.close()
self.memo_file.close() self.memo_file.close()
self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
'This file is not a valid EasyWorship database.'))
return return
# Take a stab at how text is encoded # Take a stab at how text is encoded
self.encoding = 'cp1252' self.encoding = 'cp1252'
@ -240,6 +250,8 @@ class EasyWorshipSongImport(SongImport):
self.encoding = 'cp874' self.encoding = 'cp874'
self.encoding = retrieve_windows_encoding(self.encoding) self.encoding = retrieve_windows_encoding(self.encoding)
if not self.encoding: if not self.encoding:
self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
'Could not retrieve encoding.'))
return return
# Read the field description information # Read the field description information
db_file.seek(120) db_file.seek(120)

View File

@ -99,10 +99,10 @@ from lxml import etree, objectify
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.ui.wizard import WizardStrings from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib import clean_song, VerseType
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.db import Author, Book, Song, Topic from openlp.plugins.songs.lib.db import Author, Book, Song, Topic
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
from openlp.plugins.songs.lib.xml import SongXML from openlp.plugins.songs.lib.openlyricsxml import SongXML
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -27,13 +27,13 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`mediashoutimport` module provides the functionality for importing The :mod:`mediashout` module provides the functionality for importing
a MediaShout database into the OpenLP database. a MediaShout database into the OpenLP database.
""" """
import pyodbc import pyodbc
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E'] VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E']

View File

@ -27,7 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`olpimport` module provides the functionality for importing OpenLP The :mod:`openlp` module provides the functionality for importing OpenLP
song databases into the current installation database. song databases into the current installation database.
""" """
import logging import logging

View File

@ -27,7 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`openlyricsimport` module provides the functionality for importing The :mod:`openlyrics` module provides the functionality for importing
songs which are saved as OpenLyrics files. songs which are saved as OpenLyrics files.
""" """
@ -37,9 +37,9 @@ import os
from lxml import etree from lxml import etree
from openlp.core.ui.wizard import WizardStrings from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
from openlp.plugins.songs.lib.xml import OpenLyrics, OpenLyricsError from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, OpenLyricsError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -52,7 +52,7 @@ except ImportError:
PAGE_BOTH = 6 PAGE_BOTH = 6
class OooImport(SongImport): class OpenOfficeImport(SongImport):
""" """
Import songs from Impress/Powerpoint docs using Impress Import songs from Impress/Powerpoint docs using Impress
""" """

View File

@ -35,7 +35,7 @@ from lxml.etree import Error, LxmlError
from openlp.core.common import translate from openlp.core.common import translate
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -27,7 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`powersongimport` module provides the functionality for importing The :mod:`powersong` module provides the functionality for importing
PowerSong songs into the OpenLP database. PowerSong songs into the OpenLP database.
""" """
import logging import logging
@ -35,7 +35,7 @@ import fnmatch
import os import os
from openlp.core.common import translate from openlp.core.common import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -90,7 +90,7 @@ class PowerSongImport(SongImport):
""" """
Receive either a list of files or a folder (unicode) to import. Receive either a list of files or a folder (unicode) to import.
""" """
from .importer import SongFormat from openlp.plugins.songs.lib.importer import SongFormat
ps_string = SongFormat.get(SongFormat.PowerSong, 'name') ps_string = SongFormat.get(SongFormat.PowerSong, 'name')
if isinstance(self.import_source, str): if isinstance(self.import_source, str):
if os.path.isdir(self.import_source): if os.path.isdir(self.import_source):

View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`propresenter` module provides the functionality for importing
ProPresenter song files into the current installation database.
"""
import os
import base64
from lxml import objectify
from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib import strip_rtf
from .songimport import SongImport
class ProPresenterImport(SongImport):
"""
The :class:`ProPresenterImport` class provides OpenLP with the
ability to import ProPresenter song files.
"""
def do_import(self):
self.import_wizard.progress_bar.setMaximum(len(self.import_source))
for file_path in self.import_source:
if self.stop_import_flag:
return
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
root = objectify.parse(open(file_path, 'rb')).getroot()
self.process_song(root)
def process_song(self, root):
self.set_defaults()
self.title = root.get('CCLISongTitle')
self.copyright = root.get('CCLICopyrightInfo')
self.comments = root.get('notes')
self.ccli_number = root.get('CCLILicenseNumber')
for author_key in ['author', 'artist', 'CCLIArtistCredits']:
author = root.get(author_key)
if len(author) > 0:
self.parse_author(author)
count = 0
for slide in root.slides.RVDisplaySlide:
count += 1
RTFData = slide.displayElements.RVTextElement.get('RTFData')
rtf = base64.standard_b64decode(RTFData)
words, encoding = strip_rtf(rtf.decode())
self.add_verse(words, "v%d" % count)
if not self.finish():
self.log_error(self.import_source)

View File

@ -27,7 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`songbeamerimport` module provides the functionality for importing SongBeamer songs into the OpenLP database. The :mod:`songbeamer` module provides the functionality for importing SongBeamer songs into the OpenLP database.
""" """
import chardet import chardet
import codecs import codecs
@ -36,7 +36,7 @@ import os
import re import re
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -39,7 +39,7 @@ from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib import clean_song, VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile from openlp.plugins.songs.lib.db import Song, Author, Topic, 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 SongXML from openlp.plugins.songs.lib.openlyricsxml import SongXML
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -27,13 +27,13 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`songproimport` module provides the functionality for importing SongPro The :mod:`songpro` module provides the functionality for importing SongPro
songs into the OpenLP database. songs into the OpenLP database.
""" """
import re import re
from openlp.plugins.songs.lib import strip_rtf from openlp.plugins.songs.lib import strip_rtf
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
class SongProImport(SongImport): class SongProImport(SongImport):

View File

@ -27,7 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`songshowplusimport` module provides the functionality for importing SongShow Plus songs into the OpenLP The :mod:`songshowplus` module provides the functionality for importing SongShow Plus songs into the OpenLP
database. database.
""" """
import chardet import chardet
@ -38,7 +38,7 @@ import struct
from openlp.core.ui.wizard import WizardStrings from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
TITLE = 1 TITLE = 1
AUTHOR = 2 AUTHOR = 2

View File

@ -37,13 +37,13 @@ import logging
import os import os
import re import re
from .oooimport import OooImport from .openoffice import OpenOfficeImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
if os.name == 'nt': if os.name == 'nt':
from .oooimport import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH from .openoffice import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH
RuntimeException = Exception RuntimeException = Exception
else: else:
try: try:
@ -62,7 +62,7 @@ except ImportError:
ITALIC = 2 ITALIC = 2
class SofImport(OooImport): class SongsOfFellowshipImport(OpenOfficeImport):
""" """
Import songs provided on disks with the Songs of Fellowship music books Import songs provided on disks with the Songs of Fellowship music books
VOLS1_2.RTF, sof3words.rtf and sof4words.rtf VOLS1_2.RTF, sof3words.rtf and sof4words.rtf
@ -83,7 +83,7 @@ class SofImport(OooImport):
Initialise the class. Requires a songmanager class which is passed Initialise the class. Requires a songmanager class which is passed
to SongImport for writing song to disk to SongImport for writing song to disk
""" """
OooImport.__init__(self, manager, **kwargs) OpenOfficeImport.__init__(self, manager, **kwargs)
self.song = False self.song = False
def process_ooo_document(self): def process_ooo_document(self):

View File

@ -32,7 +32,7 @@ import re
from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding
from openlp.plugins.songs.lib import strip_rtf from openlp.plugins.songs.lib import strip_rtf
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
HOTKEY_TO_VERSE_TYPE = { HOTKEY_TO_VERSE_TYPE = {
'1': 'v1', '1': 'v1',

View File

@ -27,24 +27,23 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`wowimport` module provides the functionality for importing Words of The :mod:`wordsofworship` module provides the functionality for importing Words of
Worship songs into the OpenLP database. Worship songs into the OpenLP database.
""" """
import os import os
import logging import logging
from openlp.core.common import translate from openlp.core.common import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
BLOCK_TYPES = ('V', 'C', 'B') BLOCK_TYPES = ('V', 'C', 'B')
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class WowImport(SongImport): class WordsOfWorshipImport(SongImport):
""" """
The :class:`WowImport` class provides the ability to import song files from The :class:`WordsOfWorshipImport` class provides the ability to import song files from Words of Worship.
Words of Worship.
**Words Of Worship Song File Format:** **Words Of Worship Song File Format:**

View File

@ -0,0 +1,171 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`worshipassistant` module provides the functionality for importing
Worship Assistant songs into the OpenLP database.
"""
import chardet
import csv
import logging
import re
from openlp.core.common import translate
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.importers.songimport import SongImport
log = logging.getLogger(__name__)
EMPTY_STR = 'NULL'
class WorshipAssistantImport(SongImport):
"""
The :class:`WorshipAssistantImport` class provides the ability to import songs
from Worship Assistant, via a dump of the database to a CSV file.
The following fields are in the exported CSV file:
* ``SONGNR`` Song ID (Discarded by importer)
* ``TITLE`` Song title
* ``AUTHOR`` Song author.
* ``COPYRIGHT`` Copyright information
* ``FIRSTLINE`` Unknown (Discarded by importer)
* ``PRIKEY`` Primary chord key (Discarded by importer)
* ``ALTKEY`` Alternate chord key (Discarded by importer)
* ``TEMPO`` Tempo (Discarded by importer)
* ``FOCUS`` Unknown (Discarded by importer)
* ``THEME`` Theme (Discarded by importer)
* ``SCRIPTURE`` Associated scripture (Discarded by importer)
* ``ACTIVE`` Boolean value (Discarded by importer)
* ``SONGBOOK`` Boolean value (Discarded by importer)
* ``TIMESIG`` Unknown (Discarded by importer)
* ``INTRODUCED`` Date the song was created (Discarded by importer)
* ``LASTUSED`` Date the song was last used (Discarded by importer)
* ``TIMESUSED`` How many times the song was used (Discarded by importer)
* ``CCLINR`` CCLI Number
* ``USER1`` User Field 1 (Discarded by importer)
* ``USER2`` User Field 2 (Discarded by importer)
* ``USER3`` User Field 3 (Discarded by importer)
* ``USER4`` User Field 4 (Discarded by importer)
* ``USER5`` User Field 5 (Discarded by importer)
* ``ROADMAP`` Verse order used for the presentation
* ``FILELINK1`` Associated file 1 (Discarded by importer)
* ``OVERMAP`` Verse order used for printing (Discarded by importer)
* ``FILELINK2`` Associated file 2 (Discarded by importer)
* ``LYRICS`` The song lyrics used for printing (Discarded by importer, LYRICS2 is used instead)
* ``INFO`` Unknown (Discarded by importer)
* ``LYRICS2`` The song lyrics used for the presentation
* ``BACKGROUND`` Custom background (Discarded by importer)
"""
def do_import(self):
"""
Receive a CSV file to import.
"""
# Get encoding
detect_file = open(self.import_source, 'rb')
detect_content = detect_file.read()
details = chardet.detect(detect_content)
detect_file.close()
songs_file = open(self.import_source, 'r', encoding=details['encoding'])
songs_reader = csv.DictReader(songs_file)
try:
records = list(songs_reader)
except csv.Error as e:
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'),
translate('SongsPlugin.WorshipAssistantImport', 'Line %d: %s') %
(songs_reader.line_num, e))
return
num_records = len(records)
log.info('%s records found in CSV file' % num_records)
self.import_wizard.progress_bar.setMaximum(num_records)
for index, record in enumerate(records, 1):
if self.stop_import_flag:
return
# Ensure that all keys are uppercase
record = dict((field.upper(), value) for field, value in record.items())
# The CSV file has a line in the middle of the file where the headers are repeated.
# We need to skip this line.
if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2':
continue
self.set_defaults()
verse_order_list = []
try:
self.title = record['TITLE']
if record['AUTHOR'] != EMPTY_STR:
self.parse_author(record['AUTHOR'])
print(record['AUTHOR'])
if record['COPYRIGHT'] != EMPTY_STR:
self.add_copyright(record['COPYRIGHT'])
if record['CCLINR'] != EMPTY_STR:
self.ccli_number = record['CCLINR']
if record['ROADMAP'] != EMPTY_STR:
verse_order_list = record['ROADMAP'].split(',')
lyrics = record['LYRICS2']
except UnicodeDecodeError as e:
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index),
translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: %s') % e)
continue
except TypeError as e:
self.log_error(translate('SongsPlugin.WorshipAssistantImport',
'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e)
return
verse = ''
for line in lyrics.splitlines():
if line.startswith('['): # verse marker
# drop the square brackets
right_bracket = line.find(']')
content = line[1:right_bracket].lower()
match = re.match('(\D*)(\d+)', content)
if match is not None:
verse_tag = match.group(1)
verse_num = match.group(2)
else:
# otherwise we assume number 1 and take the whole prefix as the verse tag
verse_tag = content
verse_num = '1'
verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0
verse_tag = VerseType.tags[verse_index]
# Update verse order when the verse name has changed
if content != verse_tag + verse_num:
for i in range(len(verse_order_list)):
if verse_order_list[i].lower() == content.lower():
verse_order_list[i] = verse_tag + verse_num
elif line and not line.isspace():
verse += line + '\n'
elif verse:
self.add_verse(verse, verse_tag+verse_num)
verse = ''
if verse:
self.add_verse(verse, verse_tag+verse_num)
if verse_order_list:
self.verse_order_list = verse_order_list
if not self.finish():
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d') % index
+ (': "' + self.title + '"' if self.title else ''))
songs_file.close()

View File

@ -35,7 +35,7 @@ import logging
import pyodbc import pyodbc
from openlp.core.common import translate from openlp.core.common import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -27,14 +27,13 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`zionworximport` module provides the functionality for importing The :mod:`zionworx` module provides the functionality for importing ZionWorx songs into the OpenLP database.
ZionWorx songs into the OpenLP database.
""" """
import csv import csv
import logging import logging
from openlp.core.common import translate from openlp.core.common import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -46,7 +46,7 @@ from openlp.plugins.songs.forms.songexportform import SongExportForm
from openlp.plugins.songs.lib import VerseType, clean_string, delete_song from openlp.plugins.songs.lib import VerseType, clean_string, delete_song
from openlp.plugins.songs.lib.db import Author, AuthorType, Song, Book, MediaFile from openlp.plugins.songs.lib.db import Author, AuthorType, 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.openlyricsxml import OpenLyrics, SongXML
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -37,7 +37,7 @@ from lxml import etree
from openlp.core.common import RegistryProperties, check_directory_exists, translate from openlp.core.common import RegistryProperties, check_directory_exists, translate
from openlp.core.utils import clean_filename from openlp.core.utils import clean_filename
from openlp.plugins.songs.lib.xml import OpenLyrics from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -661,7 +661,7 @@ class OpenLyrics(object):
# OpenLyrics 0.8 uses <br/> for new lines. Append text from "lines" element to verse text. # OpenLyrics 0.8 uses <br/> for new lines. Append text from "lines" element to verse text.
if version > '0.7': if version > '0.7':
text = self._process_lines_mixed_content(element) text = self._process_lines_mixed_content(element)
# OpenLyrics version <= 0.7 contais <line> elements to represent lines. First child element is tested. # OpenLyrics version <= 0.7 contains <line> elements to represent lines. First child element is tested.
else: else:
# Loop over the "line" elements removing comments and chords. # Loop over the "line" elements removing comments and chords.
for line in element: for line in element:

View File

@ -38,7 +38,7 @@ from html.parser import HTMLParser
from bs4 import BeautifulSoup, NavigableString from bs4 import BeautifulSoup, NavigableString
from openlp.plugins.songs.lib import Song, VerseType, clean_song, Author from openlp.plugins.songs.lib import Song, VerseType, clean_song, Author
from openlp.plugins.songs.lib.xml import SongXML from openlp.plugins.songs.lib.openlyricsxml import SongXML
USER_AGENT = 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; GT-I9000 ' \ USER_AGENT = 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; GT-I9000 ' \
'Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 ' \ 'Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 ' \

View File

@ -49,7 +49,7 @@ from openlp.plugins.songs.lib import clean_song, upgrade
from openlp.plugins.songs.lib.db import init_schema, Song from openlp.plugins.songs.lib.db import init_schema, Song
from openlp.plugins.songs.lib.mediaitem import SongSearch from openlp.plugins.songs.lib.mediaitem import SongSearch
from openlp.plugins.songs.lib.importer import SongFormat from openlp.plugins.songs.lib.importer import SongFormat
from openlp.plugins.songs.lib.olpimport import OpenLPSongImport from openlp.plugins.songs.lib.importers.openlp import OpenLPSongImport
from openlp.plugins.songs.lib.mediaitem import SongMediaItem from openlp.plugins.songs.lib.mediaitem import SongMediaItem
from openlp.plugins.songs.lib.songstab import SongsTab from openlp.plugins.songs.lib.songstab import SongsTab

View File

@ -63,7 +63,7 @@ import webbrowser
from optparse import OptionParser from optparse import OptionParser
from PyQt4 import QtCore from PyQt4 import QtCore
SERVER_URL = 'http://www.transifex.net/api/2/project/openlp/' SERVER_URL = 'http://www.transifex.net/api/2/project/openlp/resource/openlp-22x/'
IGNORED_PATHS = ['scripts'] IGNORED_PATHS = ['scripts']
IGNORED_FILES = ['setup.py'] IGNORED_FILES = ['setup.py']
@ -175,7 +175,7 @@ def run(command):
process = QtCore.QProcess() process = QtCore.QProcess()
process.start(command) process.start(command)
while process.waitForReadyRead(): while process.waitForReadyRead():
print_verbose('ReadyRead: %s' % QtCore.QString(process.readAll())) print_verbose('ReadyRead: %s' % process.readAll())
print_verbose('Error(s):\n%s' % process.readAllStandardError()) print_verbose('Error(s):\n%s' % process.readAllStandardError())
print_verbose('Output:\n%s' % process.readAllStandardOutput()) print_verbose('Output:\n%s' % process.readAllStandardOutput())
@ -193,27 +193,26 @@ def download_translations():
if not password: if not password:
password = getpass(' Transifex password: ') password = getpass(' Transifex password: ')
# First get the list of languages # First get the list of languages
url = SERVER_URL + 'resource/ents/' base64string = base64.encodebytes(('%s:%s' % (username, password)).encode())[:-1]
base64string = base64.encodbytes('%s:%s' % (username, password))[:-1] auth_header = 'Basic %s' % base64string.decode()
auth_header = 'Basic %s' % base64string request = urllib.request.Request(SERVER_URL + '?details')
request = urllib.request.Request(url + '?details')
request.add_header('Authorization', auth_header) request.add_header('Authorization', auth_header)
print_verbose('Downloading list of languages from: %s' % url) print_verbose('Downloading list of languages from: %s' % SERVER_URL)
try: try:
json_response = urllib.request.urlopen(request) json_response = urllib.request.urlopen(request)
except urllib.error.HTTPError: except urllib.error.HTTPError:
print_quiet('Username or password incorrect.') print_quiet('Username or password incorrect.')
return False return False
json_dict = json.loads(json_response.read()) json_dict = json.loads(json_response.read().decode())
languages = [lang['code'] for lang in json_dict['available_languages']] languages = [lang['code'] for lang in json_dict['available_languages']]
for language in languages: for language in languages:
lang_url = url + 'translation/%s/?file' % language lang_url = SERVER_URL + 'translation/%s/?file' % language
request = urllib.request.Request(lang_url) request = urllib.request.Request(lang_url)
request.add_header('Authorization', auth_header) request.add_header('Authorization', auth_header)
filename = os.path.join(os.path.abspath('..'), 'resources', 'i18n', language + '.ts') filename = os.path.join(os.path.abspath('..'), 'resources', 'i18n', language + '.ts')
print_verbose('Get Translation File: %s' % filename) print_verbose('Get Translation File: %s' % filename)
response = urllib.request.urlopen(request) response = urllib.request.urlopen(request)
fd = open(filename, 'w') fd = open(filename, 'wb')
fd.write(response.read()) fd.write(response.read())
fd.close() fd.close()
print_quiet(' Done.') print_quiet(' Done.')
@ -261,7 +260,7 @@ def prepare_project():
lines.append('TRANSLATIONS += %s' % line) lines.append('TRANSLATIONS += %s' % line)
lines.sort() lines.sort()
file = open(os.path.join(start_dir, 'openlp.pro'), 'w') file = open(os.path.join(start_dir, 'openlp.pro'), 'w')
file.write('\n'.join(lines).encode('utf8')) file.write('\n'.join(lines))
file.close() file.close()
print_quiet(' Done.') print_quiet(' Done.')

3
setup.cfg Normal file
View File

@ -0,0 +1,3 @@
[pep8]
exclude=resources.py,vlc.py
max-line-length = 120

View File

@ -32,7 +32,7 @@ Functional tests to test the AppLocation class and related methods.
from unittest import TestCase from unittest import TestCase
from openlp.core.common import de_hump, trace_error_handler from openlp.core.common import check_directory_exists, de_hump, trace_error_handler, translate
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
@ -40,6 +40,45 @@ class TestCommonFunctions(TestCase):
""" """
A test suite to test out various functions in the openlp.core.common module. A test suite to test out various functions in the openlp.core.common module.
""" """
def check_directory_exists_test(self):
"""
Test the check_directory_exists() function
"""
with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
patch('openlp.core.lib.os.makedirs') as mocked_makedirs:
# GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
directory_to_check = 'existing/directory'
# WHEN: os.path.exists returns True and we check to see if the directory exists
mocked_exists.return_value = True
check_directory_exists(directory_to_check)
# THEN: Only os.path.exists should have been called
mocked_exists.assert_called_with(directory_to_check)
self.assertIsNot(mocked_makedirs.called, 'os.makedirs should not have been called')
# WHEN: os.path.exists returns False and we check the directory exists
mocked_exists.return_value = False
check_directory_exists(directory_to_check)
# THEN: Both the mocked functions should have been called
mocked_exists.assert_called_with(directory_to_check)
mocked_makedirs.assert_called_with(directory_to_check)
# WHEN: os.path.exists raises an IOError
mocked_exists.side_effect = IOError()
check_directory_exists(directory_to_check)
# THEN: We shouldn't get an exception though the mocked exists has been called
mocked_exists.assert_called_with(directory_to_check)
# WHEN: Some other exception is raised
mocked_exists.side_effect = ValueError()
# THEN: check_directory_exists raises an exception
mocked_exists.assert_called_with(directory_to_check)
self.assertRaises(ValueError, check_directory_exists, directory_to_check)
def de_hump_conversion_test(self): def de_hump_conversion_test(self):
""" """
Test the de_hump function with a class name Test the de_hump function with a class name
@ -81,3 +120,22 @@ class TestCommonFunctions(TestCase):
# THEN: The mocked_logger.error() method should have been called with the correct parameters # THEN: The mocked_logger.error() method should have been called with the correct parameters
mocked_logger.error.assert_called_with( mocked_logger.error.assert_called_with(
'OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test') 'OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test')
def translate_test(self):
"""
Test the translate() function
"""
# GIVEN: A string to translate and a mocked Qt translate function
context = 'OpenLP.Tests'
text = 'Untranslated string'
comment = 'A comment'
encoding = 1
n = 1
mocked_translate = MagicMock(return_value='Translated string')
# WHEN: we call the translate function
result = translate(context, text, comment, encoding, n, mocked_translate)
# THEN: the translated string should be returned, and the mocked function should have been called
mocked_translate.assert_called_with(context, text, comment, encoding, n)
self.assertEqual('Translated string', result, 'The translated string should have been returned')

View File

@ -36,9 +36,8 @@ from datetime import datetime, timedelta
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.common import check_directory_exists, translate from openlp.core.lib import build_icon, check_item_selected, clean_tags, create_thumb, create_separated_list, \
from openlp.core.lib import str_to_bool, create_thumb, get_text_file_string, \ expand_tags, get_text_file_string, image_to_byte, resize_image, str_to_bool, validate_thumb
build_icon, image_to_byte, check_item_selected, validate_thumb, create_separated_list, clean_tags, expand_tags
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources')) TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
@ -152,64 +151,6 @@ class TestLib(TestCase):
# THEN: we should get back a true # THEN: we should get back a true
self.assertTrue(str_result, 'The result should be True') self.assertTrue(str_result, 'The result should be True')
def translate_test(self):
"""
Test the translate() function
"""
# GIVEN: A string to translate and a mocked Qt translate function
context = 'OpenLP.Tests'
text = 'Untranslated string'
comment = 'A comment'
encoding = 1
n = 1
mocked_translate = MagicMock(return_value='Translated string')
# WHEN: we call the translate function
result = translate(context, text, comment, encoding, n, mocked_translate)
# THEN: the translated string should be returned, and the mocked function should have been called
mocked_translate.assert_called_with(context, text, comment, encoding, n)
self.assertEqual('Translated string', result, 'The translated string should have been returned')
def check_directory_exists_test(self):
"""
Test the check_directory_exists() function
"""
with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
patch('openlp.core.lib.os.makedirs') as mocked_makedirs:
# GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
directory_to_check = 'existing/directory'
# WHEN: os.path.exists returns True and we check to see if the directory exists
mocked_exists.return_value = True
check_directory_exists(directory_to_check)
# THEN: Only os.path.exists should have been called
mocked_exists.assert_called_with(directory_to_check)
self.assertIsNot(mocked_makedirs.called, 'os.makedirs should not have been called')
# WHEN: os.path.exists returns False and we check the directory exists
mocked_exists.return_value = False
check_directory_exists(directory_to_check)
# THEN: Both the mocked functions should have been called
mocked_exists.assert_called_with(directory_to_check)
mocked_makedirs.assert_called_with(directory_to_check)
# WHEN: os.path.exists raises an IOError
mocked_exists.side_effect = IOError()
check_directory_exists(directory_to_check)
# THEN: We shouldn't get an exception though the mocked exists has been called
mocked_exists.assert_called_with(directory_to_check)
# WHEN: Some other exception is raised
mocked_exists.side_effect = ValueError()
# THEN: check_directory_exists raises an exception
mocked_exists.assert_called_with(directory_to_check)
self.assertRaises(ValueError, check_directory_exists, directory_to_check)
def get_text_file_string_no_file_test(self): def get_text_file_string_no_file_test(self):
""" """
Test the get_text_file_string() function when a file does not exist Test the get_text_file_string() function when a file does not exist
@ -353,7 +294,7 @@ class TestLib(TestCase):
Test that the check_item_selected() function returns True when there are selected indexes Test that the check_item_selected() function returns True when there are selected indexes
""" """
# GIVEN: A mocked out QtGui module and a list widget with selected indexes # GIVEN: A mocked out QtGui module and a list widget with selected indexes
MockedQtGui = patch('openlp.core.lib.QtGui') mocked_QtGui = patch('openlp.core.lib.QtGui')
mocked_list_widget = MagicMock() mocked_list_widget = MagicMock()
mocked_list_widget.selectedIndexes.return_value = True mocked_list_widget.selectedIndexes.return_value = True
message = 'message' message = 'message'
@ -508,6 +449,27 @@ class TestLib(TestCase):
mocked_os.stat.assert_any_call(thumb_path) mocked_os.stat.assert_any_call(thumb_path)
assert result is False, 'The result should be False' assert result is False, 'The result should be False'
def resize_thumb_test(self):
"""
Test the resize_thumb() function
"""
# GIVEN: A path to an image.
image_path = os.path.join(TEST_PATH, 'church.jpg')
wanted_width = 777
wanted_height = 72
# We want the background to be white.
wanted_background_hex = '#FFFFFF'
wanted_background_rgb = QtGui.QColor(wanted_background_hex).rgb()
# WHEN: Resize the image and add a background.
image = resize_image(image_path, wanted_width, wanted_height, wanted_background_hex)
# THEN: Check if the size is correct and the background was set.
result_size = image.size()
self.assertEqual(wanted_height, result_size.height(), 'The image should have the requested height.')
self.assertEqual(wanted_width, result_size.width(), 'The image should have the requested width.')
self.assertEqual(image.pixel(0, 0), wanted_background_rgb, 'The background should be white.')
def create_separated_list_qlocate_test(self): def create_separated_list_qlocate_test(self):
""" """
Test the create_separated_list function using the Qt provided method Test the create_separated_list function using the Qt provided method

View File

@ -154,6 +154,21 @@ class TestUi(TestCase):
self.assertEqual('my tooltip', action.toolTip()) self.assertEqual('my tooltip', action.toolTip())
self.assertEqual('my statustip', action.statusTip()) self.assertEqual('my statustip', action.statusTip())
def test_create_checked_enabled_visible_action(self):
"""
Test creating an action with the 'checked', 'enabled' and 'visible' properties.
"""
# GIVEN: A dialog
dialog = QtGui.QDialog()
# WHEN: We create an action with some properties
action = create_action(dialog, 'my_action', checked=True, enabled=False, visible=False)
# THEN: These properties should be set
self.assertEqual(True, action.isChecked())
self.assertEqual(False, action.isEnabled())
self.assertEqual(False, action.isVisible())
def test_create_valign_selection_widgets(self): def test_create_valign_selection_widgets(self):
""" """
Test creating a combo box for valign selection Test creating a combo box for valign selection
@ -198,6 +213,20 @@ class TestUi(TestCase):
# THEN: The index should have changed # THEN: The index should have changed
self.assertEqual(2, combo.currentIndex()) self.assertEqual(2, combo.currentIndex())
def test_create_widget_action(self):
"""
Test creating an action for a widget
"""
# GIVEN: A button
button = QtGui.QPushButton()
# WHEN: We call the function
action = create_widget_action(button, 'some action')
# THEN: The action should be returned
self.assertIsInstance(action, QtGui.QAction)
self.assertEqual(action.objectName(), 'some action')
def test_set_case_insensitive_completer(self): def test_set_case_insensitive_completer(self):
""" """
Test setting a case insensitive completer on a widget Test setting a case insensitive completer on a widget

View File

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Functional tests to test the PowerPointController class and related methods.
"""
import os
if os.name == 'nt':
import pywintypes
import shutil
from unittest import TestCase
from tempfile import mkdtemp
from tests.functional import patch, MagicMock
from tests.helpers.testmixin import TestMixin
from openlp.plugins.presentations.lib.powerpointcontroller import PowerpointController, PowerpointDocument
class TestPowerpointController(TestCase, TestMixin):
"""
Test the PowerpointController Class
"""
def setUp(self):
"""
Set up the patches and mocks need for all tests.
"""
self.get_application()
self.build_settings()
self.mock_plugin = MagicMock()
self.temp_folder = mkdtemp()
self.mock_plugin.settings_section = self.temp_folder
def tearDown(self):
"""
Stop the patches
"""
self.destroy_settings()
shutil.rmtree(self.temp_folder)
def constructor_test(self):
"""
Test the Constructor from the PowerpointController
"""
# GIVEN: No presentation controller
controller = None
# WHEN: The presentation controller object is created
controller = PowerpointController(plugin=self.mock_plugin)
# THEN: The name of the presentation controller should be correct
self.assertEqual('Powerpoint', controller.name,
'The name of the presentation controller should be correct')
class TestPowerpointDocument(TestCase):
"""
Test the PowerpointDocument Class
"""
def setUp(self):
"""
Set up the patches and mocks need for all tests.
"""
self.powerpoint_document_stop_presentation_patcher = patch(
'openlp.plugins.presentations.lib.powerpointcontroller.PowerpointDocument.stop_presentation')
self.presentation_document_get_temp_folder_patcher = patch(
'openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument.get_temp_folder')
self.presentation_document_setup_patcher = patch(
'openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument._setup')
self.mock_powerpoint_document_stop_presentation = self.powerpoint_document_stop_presentation_patcher.start()
self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start()
self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start()
self.mock_controller = MagicMock()
self.mock_presentation = MagicMock()
self.mock_presentation_document_get_temp_folder.return_value = 'temp folder'
def tearDown(self):
"""
Stop the patches
"""
self.powerpoint_document_stop_presentation_patcher.stop()
self.presentation_document_get_temp_folder_patcher.stop()
self.presentation_document_setup_patcher.stop()
def show_error_msg_test(self):
"""
Test the PowerpointDocument.show_error_msg() method gets called on com exception
"""
if os.name == 'nt':
# GIVEN: A PowerpointDocument with mocked controller and presentation
with patch('openlp.plugins.presentations.lib.powerpointcontroller.critical_error_message_box') as \
mocked_critical_error_message_box:
instance = PowerpointDocument(self.mock_controller, self.mock_presentation)
instance.presentation = MagicMock()
instance.presentation.SlideShowWindow.View.GotoSlide = MagicMock(side_effect=pywintypes.com_error('1'))
# WHEN: Calling goto_slide which will throw an exception
instance.goto_slide(42)
# THEN: mocked_critical_error_message_box should have been called
mocked_critical_error_message_box.assert_called_with('Error', 'An error occurred in the Powerpoint '
'integration and the presentation will be stopped.'
' Restart the presentation if you wish to '
'present it.')

View File

@ -35,7 +35,7 @@ from unittest import TestCase
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
from openlp.plugins.songs.lib.ewimport import EasyWorshipSongImport, FieldDescEntry, FieldType from openlp.plugins.songs.lib.importers.easyworship import EasyWorshipSongImport, FieldDescEntry, FieldType
TEST_PATH = os.path.abspath( TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'easyworshipsongs')) os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'easyworshipsongs'))
@ -178,7 +178,7 @@ class TestEasyWorshipSongImport(TestCase):
Test creating an instance of the EasyWorship file importer Test creating an instance of the EasyWorship file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created
@ -192,7 +192,7 @@ class TestEasyWorshipSongImport(TestCase):
Test finding an existing field in a given list using the :mod:`find_field` Test finding an existing field in a given list using the :mod:`find_field`
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions. # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions.
with patch('openlp.plugins.songs.lib.ewimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
importer.field_descriptions = TEST_FIELD_DESCS importer.field_descriptions = TEST_FIELD_DESCS
@ -210,7 +210,7 @@ class TestEasyWorshipSongImport(TestCase):
Test finding an non-existing field in a given list using the :mod:`find_field` Test finding an non-existing field in a given list using the :mod:`find_field`
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions
with patch('openlp.plugins.songs.lib.ewimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
importer.field_descriptions = TEST_FIELD_DESCS importer.field_descriptions = TEST_FIELD_DESCS
@ -228,8 +228,8 @@ class TestEasyWorshipSongImport(TestCase):
""" """
# GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of # GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of
# field descriptions # field descriptions
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct: patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
@ -246,7 +246,7 @@ class TestEasyWorshipSongImport(TestCase):
Test the :mod:`get_field` module Test the :mod:`get_field` module
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results # GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results
with patch('openlp.plugins.songs.lib.ewimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
importer.encoding = TEST_DATA_ENCODING importer.encoding = TEST_DATA_ENCODING
@ -269,7 +269,7 @@ class TestEasyWorshipSongImport(TestCase):
""" """
for test_results in GET_MEMO_FIELD_TEST_RESULTS: for test_results in GET_MEMO_FIELD_TEST_RESULTS:
# GIVEN: A mocked out SongImport class, a mocked out "manager", a mocked out memo_file and an encoding # GIVEN: A mocked out SongImport class, a mocked out "manager", a mocked out memo_file and an encoding
with patch('openlp.plugins.songs.lib.ewimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_memo_file = MagicMock() mocked_memo_file = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
@ -300,8 +300,8 @@ class TestEasyWorshipSongImport(TestCase):
Test the :mod:`do_import` module opens the correct files Test the :mod:`do_import` module opens the correct files
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" # GIVEN: A mocked out SongImport class, a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.side_effect = [True, False] mocked_os_path.isfile.side_effect = [True, False]
@ -314,13 +314,33 @@ class TestEasyWorshipSongImport(TestCase):
mocked_os_path.isfile.assert_any_call('Songs.DB') mocked_os_path.isfile.assert_any_call('Songs.DB')
mocked_os_path.isfile.assert_any_call('Songs.MB') mocked_os_path.isfile.assert_any_call('Songs.MB')
def do_import_source_invalid_test(self):
"""
Test the :mod:`do_import` module produces an error when Songs.MB not found.
"""
# GIVEN: A mocked out SongImport class, a mocked out "manager"
with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path:
mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[])
importer.log_error = MagicMock()
mocked_os_path.isfile.side_effect = [True, False]
# WHEN: do_import is supplied with an import source (Songs.MB missing)
importer.import_source = 'Songs.DB'
importer.do_import()
# THEN: do_import should have logged an error that the Songs.MB file could not be found.
importer.log_error.assert_any_call(importer.import_source, 'Could not find the "Songs.MB" file. It must be '
'in the same folder as the "Songs.DB" file.')
def do_import_database_validity_test(self): def do_import_database_validity_test(self):
""" """
Test the :mod:`do_import` module handles invalid database files correctly Test the :mod:`do_import` module handles invalid database files correctly
""" """
# GIVEN: A mocked out SongImport class, os.path and a mocked out "manager" # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.return_value = True mocked_os_path.isfile.return_value = True
@ -338,10 +358,10 @@ class TestEasyWorshipSongImport(TestCase):
Test the :mod:`do_import` module handles invalid memo files correctly Test the :mod:`do_import` module handles invalid memo files correctly
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" # GIVEN: A mocked out SongImport class, a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \ patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \
patch('builtins.open') as mocked_open, \ patch('builtins.open') as mocked_open, \
patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct: patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
mocked_os_path.isfile.return_value = True mocked_os_path.isfile.return_value = True
@ -365,10 +385,10 @@ class TestEasyWorshipSongImport(TestCase):
Test the :mod:`do_import` converts the code page to the encoding correctly Test the :mod:`do_import` converts the code page to the encoding correctly
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" # GIVEN: A mocked out SongImport class, a mocked out "manager"
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \ patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \
patch('builtins.open'), patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct, \ patch('builtins.open'), patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct, \
patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as \ patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \
mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding:
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer = EasyWorshipSongImport(mocked_manager, filenames=[])
@ -393,8 +413,8 @@ class TestEasyWorshipSongImport(TestCase):
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # 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. # and mocked out "author", "add_copyright", "add_verse", "finish" methods.
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as \ patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \
mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding:
mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_retrieve_windows_encoding.return_value = 'cp1252'
mocked_manager = MagicMock() mocked_manager = MagicMock()
@ -449,8 +469,8 @@ class TestEasyWorshipSongImport(TestCase):
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # 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. # and mocked out "author", "add_copyright", "add_verse", "finish" methods.
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') \ patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') \
as mocked_retrieve_windows_encoding: as mocked_retrieve_windows_encoding:
mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_retrieve_windows_encoding.return_value = 'cp1252'
mocked_manager = MagicMock() mocked_manager = MagicMock()
@ -489,7 +509,7 @@ class TestEasyWorshipSongImport(TestCase):
""" """
# GIVEN: A mocked out SongImport class, a mocked out "manager" and mocked out "author" method. # GIVEN: A mocked out SongImport class, a mocked out "manager" and mocked out "author" method.
with patch('openlp.plugins.songs.lib.ewimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_add_author = MagicMock() mocked_add_author = MagicMock()
importer = EasyWorshipSongImportLogger(mocked_manager) importer = EasyWorshipSongImportLogger(mocked_manager)

View File

@ -34,7 +34,7 @@ import os
from unittest import TestCase from unittest import TestCase
from tests.functional import patch, MagicMock from tests.functional import patch, MagicMock
from openlp.plugins.songs.lib.foilpresenterimport import FoilPresenter from openlp.plugins.songs.lib.importers.foilpresenter import FoilPresenter
TEST_PATH = os.path.abspath( TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', '/resources/foilpresentersongs')) os.path.join(os.path.dirname(__file__), '..', '..', '..', '/resources/foilpresentersongs'))
@ -57,27 +57,27 @@ class TestFoilPresenter(TestCase):
# _process_topics # _process_topics
def setUp(self): def setUp(self):
self.child_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._child') self.child_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._child')
self.clean_song_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.clean_song') self.clean_song_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.clean_song')
self.objectify_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.objectify') self.objectify_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.objectify')
self.process_authors_patcher = \ self.process_authors_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_authors') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_authors')
self.process_cclinumber_patcher = \ self.process_cclinumber_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_cclinumber') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_cclinumber')
self.process_comments_patcher = \ self.process_comments_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_comments') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_comments')
self.process_lyrics_patcher = \ self.process_lyrics_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_lyrics') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_lyrics')
self.process_songbooks_patcher = \ self.process_songbooks_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_songbooks') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_songbooks')
self.process_titles_patcher = \ self.process_titles_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_titles') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_titles')
self.process_topics_patcher = \ self.process_topics_patcher = \
patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_topics') patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_topics')
self.re_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.re') self.re_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.re')
self.song_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.Song') self.song_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.Song')
self.song_xml_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.SongXML') self.song_xml_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.SongXML')
self.translate_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.translate') self.translate_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.translate')
self.mocked_child = self.child_patcher.start() self.mocked_child = self.child_patcher.start()
self.mocked_clean_song = self.clean_song_patcher.start() self.mocked_clean_song = self.clean_song_patcher.start()

View File

@ -34,8 +34,8 @@ import os
from unittest import TestCase from unittest import TestCase
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
from openlp.plugins.songs.lib.openlyricsimport import OpenLyricsImport from openlp.plugins.songs.lib.importers.openlyrics import OpenLyricsImport
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', 'resources', 'openlyricssongs')) '..', '..', '..', 'resources', 'openlyricssongs'))
@ -69,7 +69,7 @@ class TestOpenLyricsImport(TestCase):
Test creating an instance of the OpenLyrics file importer Test creating an instance of the OpenLyrics file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.openlyrics.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created

View File

@ -34,7 +34,7 @@ import os
from unittest import TestCase from unittest import TestCase
from tests.helpers.songfileimport import SongImportTestHelper from tests.helpers.songfileimport import SongImportTestHelper
from openlp.plugins.songs.lib.opensongimport import OpenSongImport from openlp.plugins.songs.lib.importers.opensong import OpenSongImport
from tests.functional import patch, MagicMock from tests.functional import patch, MagicMock
TEST_PATH = os.path.abspath( TEST_PATH = os.path.abspath(
@ -45,18 +45,18 @@ class TestOpenSongFileImport(SongImportTestHelper):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.importer_class_name = 'OpenSongImport' self.importer_class_name = 'OpenSongImport'
self.importer_module_name = 'opensongimport' self.importer_module_name = 'opensong'
super(TestOpenSongFileImport, self).__init__(*args, **kwargs) super(TestOpenSongFileImport, self).__init__(*args, **kwargs)
def test_song_import(self): def test_song_import(self):
""" """
Test that loading an OpenSong file works correctly on various files Test that loading an OpenSong file works correctly on various files
""" """
self.file_import(os.path.join(TEST_PATH, 'Amazing Grace'), self.file_import([os.path.join(TEST_PATH, 'Amazing Grace')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
self.file_import(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer'), self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
self.file_import(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five'), self.file_import([os.path.join(TEST_PATH, 'One, Two, Three, Four, Five')],
self.load_external_result_data(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five.json')))
@ -69,7 +69,7 @@ class TestOpenSongImport(TestCase):
Test creating an instance of the OpenSong file importer Test creating an instance of the OpenSong file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.opensongimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created
@ -83,7 +83,7 @@ class TestOpenSongImport(TestCase):
Test OpenSongImport.do_import handles different invalid import_source values Test OpenSongImport.do_import handles different invalid import_source values
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.opensongimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
importer = OpenSongImport(mocked_manager, filenames=[]) importer = OpenSongImport(mocked_manager, filenames=[])
@ -104,7 +104,7 @@ class TestOpenSongImport(TestCase):
Test OpenSongImport.do_import handles different invalid import_source values Test OpenSongImport.do_import handles different invalid import_source values
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.opensongimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
importer = OpenSongImport(mocked_manager, filenames=[]) importer = OpenSongImport(mocked_manager, filenames=[])

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`propresenterimport` module provides the functionality for importing
ProPresenter song files into the current installation database.
"""
import os
from tests.helpers.songfileimport import SongImportTestHelper
TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'propresentersongs'))
class TestProPresenterFileImport(SongImportTestHelper):
def __init__(self, *args, **kwargs):
self.importer_class_name = 'ProPresenterImport'
self.importer_module_name = 'propresenter'
super(TestProPresenterFileImport, self).__init__(*args, **kwargs)
def test_song_import(self):
"""
Test that loading an ProPresenter file works correctly
"""
self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))

View File

@ -34,7 +34,7 @@ import os
from unittest import TestCase from unittest import TestCase
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
from openlp.plugins.songs.lib.songbeamerimport import SongBeamerImport from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
@ -64,7 +64,7 @@ class TestSongBeamerImport(TestCase):
Test creating an instance of the SongBeamer file importer Test creating an instance of the SongBeamer file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created
@ -78,7 +78,7 @@ class TestSongBeamerImport(TestCase):
Test SongBeamerImport.do_import handles different invalid import_source values Test SongBeamerImport.do_import handles different invalid import_source values
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
importer = SongBeamerImport(mocked_manager, filenames=[]) importer = SongBeamerImport(mocked_manager, filenames=[])
@ -99,7 +99,7 @@ class TestSongBeamerImport(TestCase):
Test SongBeamerImport.do_import handles different invalid import_source values Test SongBeamerImport.do_import handles different invalid import_source values
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
importer = SongBeamerImport(mocked_manager, filenames=[]) importer = SongBeamerImport(mocked_manager, filenames=[])
@ -122,7 +122,7 @@ class TestSongBeamerImport(TestCase):
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # 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. # and mocked out "author", "add_copyright", "add_verse", "finish" methods.
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'):
for song_file in SONG_TEST_DATA: for song_file in SONG_TEST_DATA:
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()

View File

@ -35,7 +35,7 @@ from unittest import TestCase
from tests.helpers.songfileimport import SongImportTestHelper from tests.helpers.songfileimport import SongImportTestHelper
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.songshowplusimport import SongShowPlusImport from openlp.plugins.songs.lib.importers.songshowplus import SongShowPlusImport
from tests.functional import patch, MagicMock from tests.functional import patch, MagicMock
TEST_PATH = os.path.abspath( TEST_PATH = os.path.abspath(
@ -46,18 +46,18 @@ class TestSongShowPlusFileImport(SongImportTestHelper):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.importer_class_name = 'SongShowPlusImport' self.importer_class_name = 'SongShowPlusImport'
self.importer_module_name = 'songshowplusimport' self.importer_module_name = 'songshowplus'
super(TestSongShowPlusFileImport, self).__init__(*args, **kwargs) super(TestSongShowPlusFileImport, self).__init__(*args, **kwargs)
def test_song_import(self): def test_song_import(self):
""" """
Test that loading a SongShow Plus file works correctly on various files Test that loading a SongShow Plus file works correctly on various files
""" """
self.file_import(os.path.join(TEST_PATH, 'Amazing Grace.sbsong'), self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sbsong')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
self.file_import(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong'), self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
self.file_import(os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong'), self.file_import([os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong')],
self.load_external_result_data(os.path.join(TEST_PATH, 'a mighty fortress is our god.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'a mighty fortress is our god.json')))
@ -70,7 +70,7 @@ class TestSongShowPlusImport(TestCase):
Test creating an instance of the SongShow Plus file importer Test creating an instance of the SongShow Plus file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created
@ -84,7 +84,7 @@ class TestSongShowPlusImport(TestCase):
Test SongShowPlusImport.do_import handles different invalid import_source values Test SongShowPlusImport.do_import handles different invalid import_source values
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
importer = SongShowPlusImport(mocked_manager, filenames=[]) importer = SongShowPlusImport(mocked_manager, filenames=[])
@ -105,7 +105,7 @@ class TestSongShowPlusImport(TestCase):
Test SongShowPlusImport.do_import handles different invalid import_source values Test SongShowPlusImport.do_import handles different invalid import_source values
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
importer = SongShowPlusImport(mocked_manager, filenames=[]) importer = SongShowPlusImport(mocked_manager, filenames=[])
@ -126,7 +126,7 @@ class TestSongShowPlusImport(TestCase):
Test to_openlp_verse_tag method by simulating adding a verse Test to_openlp_verse_tag method by simulating adding a verse
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = SongShowPlusImport(mocked_manager, filenames=[]) importer = SongShowPlusImport(mocked_manager, filenames=[])
@ -154,7 +154,7 @@ class TestSongShowPlusImport(TestCase):
Test to_openlp_verse_tag method by simulating adding a verse to the verse order 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" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
importer = SongShowPlusImport(mocked_manager, filenames=[]) importer = SongShowPlusImport(mocked_manager, filenames=[])

View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`worshipassistantimport` module provides the functionality for importing
WorshipAssistant song files into the current installation database.
"""
import os
from tests.helpers.songfileimport import SongImportTestHelper
TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'worshipassistantsongs'))
class TestWorshipAssistantFileImport(SongImportTestHelper):
def __init__(self, *args, **kwargs):
self.importer_class_name = 'WorshipAssistantImport'
self.importer_module_name = 'worshipassistant'
super(TestWorshipAssistantFileImport, self).__init__(*args, **kwargs)
def test_song_import(self):
"""
Test that loading an Worship Assistant file works correctly
"""
self.file_import(os.path.join(TEST_PATH, 'du_herr.csv'),
self.load_external_result_data(os.path.join(TEST_PATH, 'du_herr.json')))
self.file_import(os.path.join(TEST_PATH, 'would_you_be_free.csv'),
self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))

View File

@ -37,7 +37,7 @@ if os.name != 'nt':
import pyodbc import pyodbc
from openlp.plugins.songs.lib.worshipcenterproimport import WorshipCenterProImport from openlp.plugins.songs.lib.importers.worshipcenterpro import WorshipCenterProImport
from tests.functional import patch, MagicMock from tests.functional import patch, MagicMock
@ -141,7 +141,7 @@ class TestWorshipCenterProSongImport(TestCase):
Test creating an instance of the WorshipCenter Pro file importer Test creating an instance of the WorshipCenter Pro file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.worshipcenterpro.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created
@ -156,9 +156,10 @@ class TestWorshipCenterProSongImport(TestCase):
""" """
# GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method, # GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method,
# a mocked "manager" and a mocked out log_error method. # a mocked "manager" and a mocked out log_error method.
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.worshipcenterpro.SongImport'), \
patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \ patch('openlp.plugins.songs.lib.importers.worshipcenterpro.pyodbc.connect') \
patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: as mocked_pyodbc_connect, \
patch('openlp.plugins.songs.lib.importers.worshipcenterpro.translate') as mocked_translate:
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_log_error = MagicMock() mocked_log_error = MagicMock()
mocked_translate.return_value = 'Translated Text' mocked_translate.return_value = 'Translated Text'
@ -185,9 +186,9 @@ class TestWorshipCenterProSongImport(TestCase):
""" """
# GIVEN: A mocked out SongImport class, a mocked out pyodbc module with a simulated recordset, a mocked out # GIVEN: A mocked out SongImport class, a mocked out pyodbc module with a simulated recordset, a mocked out
# translate method, a mocked "manager", add_verse method & mocked_finish method. # translate method, a mocked "manager", add_verse method & mocked_finish method.
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ with patch('openlp.plugins.songs.lib.importers.worshipcenterpro.SongImport'), \
patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ patch('openlp.plugins.songs.lib.importers.worshipcenterpro.pyodbc') as mocked_pyodbc, \
patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: patch('openlp.plugins.songs.lib.importers.worshipcenterpro.translate') as mocked_translate:
mocked_manager = MagicMock() mocked_manager = MagicMock()
mocked_import_wizard = MagicMock() mocked_import_wizard = MagicMock()
mocked_add_verse = MagicMock() mocked_add_verse = MagicMock()

View File

@ -33,8 +33,8 @@ This module contains tests for the ZionWorx song importer.
from unittest import TestCase from unittest import TestCase
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
from openlp.plugins.songs.lib.zionworximport import ZionWorxImport from openlp.plugins.songs.lib.importers.zionworx import ZionWorxImport
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.importers.songimport import SongImport
class TestZionWorxImport(TestCase): class TestZionWorxImport(TestCase):
@ -46,7 +46,7 @@ class TestZionWorxImport(TestCase):
Test creating an instance of the ZionWorx file importer Test creating an instance of the ZionWorx file importer
""" """
# GIVEN: A mocked out SongImport class, and a mocked out "manager" # GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): with patch('openlp.plugins.songs.lib.importers.zionworx.SongImport'):
mocked_manager = MagicMock() mocked_manager = MagicMock()
# WHEN: An importer object is created # WHEN: An importer object is created

View File

@ -42,23 +42,24 @@ class SongImportTestHelper(TestCase):
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(SongImportTestHelper, self).__init__(*args, **kwargs) super(SongImportTestHelper, self).__init__(*args, **kwargs)
self.importer_module = __import__( self.importer_module = __import__('openlp.plugins.songs.lib.importers.%s' %
'openlp.plugins.songs.lib.%s' % self.importer_module_name, fromlist=[self.importer_class_name]) self.importer_module_name, fromlist=[self.importer_class_name])
self.importer_class = getattr(self.importer_module, self.importer_class_name) self.importer_class = getattr(self.importer_module, self.importer_class_name)
def setUp(self): def setUp(self):
""" """
Patch and set up the mocks required. Patch and set up the mocks required.
""" """
self.add_copyright_patcher = patch( self.add_copyright_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_copyright' %
'openlp.plugins.songs.lib.%s.%s.add_copyright' % (self.importer_module_name, self.importer_class_name)) (self.importer_module_name, self.importer_class_name))
self.add_verse_patcher = patch( self.add_verse_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_verse' %
'openlp.plugins.songs.lib.%s.%s.add_verse' % (self.importer_module_name, self.importer_class_name)) (self.importer_module_name, self.importer_class_name))
self.finish_patcher = patch( self.finish_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.finish' %
'openlp.plugins.songs.lib.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) (self.importer_module_name, self.importer_class_name))
self.add_author_patcher = patch( self.add_author_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_author' %
'openlp.plugins.songs.lib.%s.%s.add_author' % (self.importer_module_name, self.importer_class_name)) (self.importer_module_name, self.importer_class_name))
self.song_import_patcher = patch('openlp.plugins.songs.lib.%s.SongImport' % self.importer_module_name) self.song_import_patcher = patch('openlp.plugins.songs.lib.importers.%s.SongImport' %
self.importer_module_name)
self.mocked_add_copyright = self.add_copyright_patcher.start() self.mocked_add_copyright = self.add_copyright_patcher.start()
self.mocked_add_verse = self.add_verse_patcher.start() self.mocked_add_verse = self.add_verse_patcher.start()
self.mocked_finish = self.finish_patcher.start() self.mocked_finish = self.finish_patcher.start()
@ -95,7 +96,7 @@ class SongImportTestHelper(TestCase):
importer.topics = [] importer.topics = []
# WHEN: Importing the source file # WHEN: Importing the source file
importer.import_source = [source_file_name] importer.import_source = source_file_name
add_verse_calls = self._get_data(result_data, 'verses') add_verse_calls = self._get_data(result_data, 'verses')
author_calls = self._get_data(result_data, 'authors') author_calls = self._get_data(result_data, 'authors')
ccli_number = self._get_data(result_data, 'ccli_number') ccli_number = self._get_data(result_data, 'ccli_number')

View File

@ -88,7 +88,7 @@ class TestPluginManager(TestCase, TestMixin):
plugin_names = [plugin.name for plugin in plugin_manager.plugins] plugin_names = [plugin.name for plugin in plugin_manager.plugins]
assert 'songs' in plugin_names, 'There should be a "songs" plugin.' assert 'songs' in plugin_names, 'There should be a "songs" plugin.'
assert 'bibles' in plugin_names, 'There should be a "bibles" plugin.' assert 'bibles' in plugin_names, 'There should be a "bibles" plugin.'
assert 'presentations' not in plugin_names, 'There should NOT be a "presentations" plugin.' assert 'presentations' in plugin_names, 'There should be a "presentations" plugin.'
assert 'images' in plugin_names, 'There should be a "images" plugin.' assert 'images' in plugin_names, 'There should be a "images" plugin.'
assert 'media' in plugin_names, 'There should be a "media" plugin.' assert 'media' in plugin_names, 'There should be a "media" plugin.'
assert 'custom' in plugin_names, 'There should be a "custom" plugin.' assert 'custom' in plugin_names, 'There should be a "custom" plugin.'

View File

@ -0,0 +1,121 @@
{
"authors": [
"John Newton"
],
"title": "Amazing Grace",
"verse_order_list": [],
"verses": [
[
"Amazing grace! How sweet the sound\n",
"v1"
],
[
"That saved a wretch like me!\n",
"v2"
],
[
"I once was lost, but now am found;\n",
"v3"
],
[
"Was blind, but now I see.\n",
"v4"
],
[
"'Twas grace that taught my heart to fear,\n",
"v5"
],
[
"And grace my fears relieved;\n",
"v6"
],
[
"How precious did that grace appear\n",
"v7"
],
[
"The hour I first believed.\n",
"v8"
],
[
"Through many dangers, toils and snares,\n",
"v9"
],
[
"I have already come;\n",
"v10"
],
[
"'Tis grace hath brought me safe thus far,\n",
"v11"
],
[
"And grace will lead me home.\n",
"v12"
],
[
"The Lord has promised good to me,\n",
"v13"
],
[
"His Word my hope secures;\n",
"v14"
],
[
"He will my Shield and Portion be,\n",
"v15"
],
[
"As long as life endures.\n",
"v16"
],
[
"Yea, when this flesh and heart shall fail,\n",
"v17"
],
[
"And mortal life shall cease,\n",
"v18"
],
[
"I shall possess, within the veil,\n",
"v19"
],
[
"A life of joy and peace.\n",
"v20"
],
[
"The earth shall soon dissolve like snow,\n",
"v21"
],
[
"The sun forbear to shine;\n",
"v22"
],
[
"But God, Who called me here below,\n",
"v23"
],
[
"Shall be forever mine.\n",
"v24"
],
[
"When we've been there ten thousand years,\n",
"v25"
],
[
"Bright shining as the sun,\n",
"v26"
],
[
"We've no less days to sing God's praise\n",
"v27"
],
[
"Than when we'd first begun.\n",
"v28"
]
]
}

View File

@ -0,0 +1,486 @@
<?xml version="1.0"?>
<RVPresentationDocument height="768" width="1024" versionNumber="401" creatorCode="1349676880" lastDateUsed="2014-06-09T07:47:29+0000" category="Hymn" backgroundColor="0 0 0 1" drawingBackgroundColor="0" notes="" artist="John Newton" author="" album="" CCLIDisplay="0" CCLIArtistCredits="" CCLISongTitle="Amazing Grace" CCLIPublisher="" CCLICopyrightInfo="" CCLILicenseNumber="" resourcesDirectory="">
<slides containerClass="NSMutableArray">
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="0" UUID="A67250CF-0DCC-4169-80EA-7E417CC233B3" drawingBackgroundColor="0" serialization-array-index="0">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbWF6aW5nIGdyYWNlISBIb3cgc3dlZXQgdGhlIHNvdW5kfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="1" UUID="B09CAF20-B402-43C3-AA35-C09B1A2CEB25" drawingBackgroundColor="0" serialization-array-index="1">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGF0IHNhdmVkIGEgd3JldGNoIGxpa2UgbWUhfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="2" UUID="CCF908FC-0FE4-4C16-BE70-9543C2A76DC7" drawingBackgroundColor="0" serialization-array-index="2">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIG9uY2Ugd2FzIGxvc3QsIGJ1dCBub3cgYW0gZm91bmQ7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="3" UUID="B33AF602-61BB-47FE-95E3-98640D6BD76A" drawingBackgroundColor="0" serialization-array-index="3">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXYXMgYmxpbmQsIGJ1dCBub3cgSSBzZWUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="4" UUID="02932C9A-C505-4856-A48E-339CA927B020" drawingBackgroundColor="0" serialization-array-index="4">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCAnVHdhcyBncmFjZSB0aGF0IHRhdWdodCBteSBoZWFydCB0byBmZWFyLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="5" UUID="F6FC7C3F-2A38-4D63-83B1-7EDA30371535" drawingBackgroundColor="0" serialization-array-index="5">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgZ3JhY2UgbXkgZmVhcnMgcmVsaWV2ZWQ7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="6" UUID="EEBFE94B-D0F2-4E41-BBE7-B5A7D4F62243" drawingBackgroundColor="0" serialization-array-index="6">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIb3cgcHJlY2lvdXMgZGlkIHRoYXQgZ3JhY2UgYXBwZWFyfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="7" UUID="0CDDEA18-F48E-4B85-8054-01140192EDC7" drawingBackgroundColor="0" serialization-array-index="7">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgaG91ciBJIGZpcnN0IGJlbGlldmVkLn1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="8" UUID="E1193588-A9B8-4371-8DC0-F16DC6D3B489" drawingBackgroundColor="0" serialization-array-index="8">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaHJvdWdoIG1hbnkgZGFuZ2VycywgdG9pbHMgYW5kIHNuYXJlcyx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="9" UUID="EBD1940D-7360-4E04-9E8F-E752B1F9ECBF" drawingBackgroundColor="0" serialization-array-index="9">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIGhhdmUgYWxyZWFkeSBjb21lO31cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="10" UUID="76F80153-DF39-4CE8-B186-79D548C596F5" drawingBackgroundColor="0" serialization-array-index="10">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCAnVGlzIGdyYWNlIGhhdGggYnJvdWdodCBtZSBzYWZlIHRodXMgZmFyLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="11" UUID="D4E43B14-8E57-44AA-BCD3-0B1F1401A829" drawingBackgroundColor="0" serialization-array-index="11">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgZ3JhY2Ugd2lsbCBsZWFkIG1lIGhvbWUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="12" UUID="D5B3DFC2-6C99-447B-A1E9-815F1550397F" drawingBackgroundColor="0" serialization-array-index="12">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgTG9yZCBoYXMgcHJvbWlzZWQgZ29vZCB0byBtZSx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="13" UUID="E1573057-DB07-4442-BDCD-1C44B5B62A60" drawingBackgroundColor="0" serialization-array-index="13">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIaXMgV29yZCBteSBob3BlIHNlY3VyZXM7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="14" UUID="D07DB5AA-710D-40F5-8FF0-C336B7C99B29" drawingBackgroundColor="0" serialization-array-index="14">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIZSB3aWxsIG15IFNoaWVsZCBhbmQgUG9ydGlvbiBiZSx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="15" UUID="0D91E879-8C6A-4C68-A098-80E95E89F4F7" drawingBackgroundColor="0" serialization-array-index="15">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBcyBsb25nIGFzIGxpZmUgZW5kdXJlcy59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="16" UUID="5105264F-D786-453E-8D29-3ADC8D84C53F" drawingBackgroundColor="0" serialization-array-index="16">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBZZWEsIHdoZW4gdGhpcyBmbGVzaCBhbmQgaGVhcnQgc2hhbGwgZmFpbCx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="17" UUID="46D46358-A465-425E-866D-1D5E215952E4" drawingBackgroundColor="0" serialization-array-index="17">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgbW9ydGFsIGxpZmUgc2hhbGwgY2Vhc2UsfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="18" UUID="8B92AC4F-1470-416E-80CA-E088EF6F3AC4" drawingBackgroundColor="0" serialization-array-index="18">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIHNoYWxsIHBvc3Nlc3MsIHdpdGhpbiB0aGUgdmVpbCx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="19" UUID="D0865E31-B064-4817-B027-A35C231D4946" drawingBackgroundColor="0" serialization-array-index="19">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBIGxpZmUgb2Ygam95IGFuZCBwZWFjZS59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="20" UUID="28AC1D6E-1F79-4E88-80A4-CA318A634046" drawingBackgroundColor="0" serialization-array-index="20">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgZWFydGggc2hhbGwgc29vbiBkaXNzb2x2ZSBsaWtlIHNub3csfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="21" UUID="3E97F36D-D9CE-4C2B-AE1A-D337A43FD7F5" drawingBackgroundColor="0" serialization-array-index="21">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgc3VuIGZvcmJlYXIgdG8gc2hpbmU7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="22" UUID="81E336F4-7170-47B0-B829-4E4A945A755F" drawingBackgroundColor="0" serialization-array-index="22">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBCdXQgR29kLCBXaG8gY2FsbGVkIG1lIGhlcmUgYmVsb3csfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="23" UUID="4D669087-EB91-4972-A1F7-D866F339C502" drawingBackgroundColor="0" serialization-array-index="23">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBTaGFsbCBiZSBmb3JldmVyIG1pbmUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="24" UUID="ADE5EE3D-56A6-4439-96DD-51C53337D4B1" drawingBackgroundColor="0" serialization-array-index="24">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXaGVuIHdlJ3ZlIGJlZW4gdGhlcmUgdGVuIHRob3VzYW5kIHllYXJzLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="25" UUID="BD68D875-5154-485A-AEF3-D48D9CE27C05" drawingBackgroundColor="0" serialization-array-index="25">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBCcmlnaHQgc2hpbmluZyBhcyB0aGUgc3VuLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="26" UUID="030026EE-A25C-4781-883D-0CAC394ADC93" drawingBackgroundColor="0" serialization-array-index="26">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXZSd2ZSBubyBsZXNzIGRheXMgdG8gc2luZyBHb2QncyBwcmFpc2V9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="27" UUID="50648C63-C1FC-40E0-8928-FEDFFCDA9689" drawingBackgroundColor="0" serialization-array-index="27">
<cues containerClass="NSMutableArray" />
<displayElements containerClass="NSMutableArray">
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGFuIHdoZW4gd2UnZCBmaXJzdCBiZWd1bi59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" serialization-array-index="0">
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
<_-D-_serializedShadow containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
</_-D-_serializedShadow>
<stroke containerClass="NSMutableDictionary">
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
</stroke>
</RVTextElement>
</displayElements>
</RVDisplaySlide>
</slides>
<timeline timeOffSet="0" selectedMediaTrackIndex="-1" unitOfMeasure="60" duration="0" loop="0">
<timeCues containerClass="NSMutableArray" />
<mediaTracks containerClass="NSMutableArray" />
</timeline>
<bibleReference containerClass="NSMutableDictionary" />
</RVPresentationDocument>

View File

@ -0,0 +1,30 @@
"SongID","SongNr","Title","Author","Copyright","FirstLine","PriKey","AltKey","Tempo","Focus","Theme","Scripture","Active","Songbook","TimeSig","Introduced","LastUsed","TimesUsed","CCLINr","User1","User2","User3","User4","User5","Roadmap","Overmap","FileLink1","FileLink2","Updated","Lyrics","Info","Lyrics2","Background"
"4ee399dc-edda-4aa9-891e-a859ca093c78","NULL","Du, Herr, verläßt mich nicht","Carl Brockhaus / Johann Georg Bäßler 1806","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","1","1","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2014-06-25 12:15:28.317","","NULL","[1]
Du, Herr, verläßt mich nicht.
Auf Dich mein Herz allein vertraut,
Mein Auge glaubend auf Dich schaut.
Du bist mein Heil, mein Licht,
Mein Fels, mein sichrer Hort.
Bin ich versucht, gibt's Not und Leid,
Du bleibst mein Trost, mein Arm im Streit,
Mein Licht am dunklen Ort.
[2]
Ich weiß, daß Du mich liebst.
Bist mir in jeder Lage nah',
Wohin ich gehe Du bist da,
Ja, Du mir alles gibst.
Ich überlaß mich Dir;
Denn Du, Herr, kennst mich ganz und gar
Und führst mich sicher, wunderbar,
Und bist selbst alles mir.
[3]
In dieser Wüste hier
Find't nirgend meine Seele Ruh',
Denn meine Ruh' bist, Jesu, Du.
Wohl mir, ich geh' zu Dir!
Bald werd' ich bei Dir sein,
Bald mit den Deinen ewiglich
Anbeten, loben, preisen Dich,
Mich Deiner stets erfreun.","NULL"
1 SongID SongNr Title Author Copyright FirstLine PriKey AltKey Tempo Focus Theme Scripture Active Songbook TimeSig Introduced LastUsed TimesUsed CCLINr User1 User2 User3 User4 User5 Roadmap Overmap FileLink1 FileLink2 Updated Lyrics Info Lyrics2 Background
2 4ee399dc-edda-4aa9-891e-a859ca093c78 NULL Du, Herr, verläßt mich nicht Carl Brockhaus / Johann Georg Bäßler 1806 NULL NULL NULL NULL NULL NULL NULL NULL 1 1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 2014-06-25 12:15:28.317 NULL [1] Du, Herr, verläßt mich nicht. Auf Dich mein Herz allein vertraut, Mein Auge glaubend auf Dich schaut. Du bist mein Heil, mein Licht, Mein Fels, mein sichrer Hort. Bin ich versucht, gibt's Not und Leid, Du bleibst mein Trost, mein Arm im Streit, Mein Licht am dunklen Ort. [2] Ich weiß, daß Du mich liebst. Bist mir in jeder Lage nah', Wohin ich gehe – Du bist da, Ja, Du mir alles gibst. Ich überlaß mich Dir; Denn Du, Herr, kennst mich ganz und gar Und führst mich sicher, wunderbar, Und bist selbst alles mir. [3] In dieser Wüste hier Find't nirgend meine Seele Ruh', Denn meine Ruh' bist, Jesu, Du. Wohl mir, ich geh' zu Dir! Bald werd' ich bei Dir sein, Bald mit den Deinen ewiglich Anbeten, loben, preisen Dich, Mich Deiner stets erfreun. NULL

View File

@ -0,0 +1,21 @@
{
"authors": [
"Carl Brockhaus / Johann Georg Bäßler 1806"
],
"title": "Du, Herr, verläßt mich nicht",
"verse_order_list": [],
"verses": [
[
"Du, Herr, verläßt mich nicht.\nAuf Dich mein Herz allein vertraut,\nMein Auge glaubend auf Dich schaut.\nDu bist mein Heil, mein Licht,\nMein Fels, mein sichrer Hort.\nBin ich versucht, gibt's Not und Leid,\nDu bleibst mein Trost, mein Arm im Streit,\nMein Licht am dunklen Ort.\n",
"v1"
],
[
"Ich weiß, daß Du mich liebst.\nBist mir in jeder Lage nah',\nWohin ich gehe Du bist da,\nJa, Du mir alles gibst.\nIch überlaß mich Dir;\nDenn Du, Herr, kennst mich ganz und gar\nUnd führst mich sicher, wunderbar,\nUnd bist selbst alles mir.\n",
"v2"
],
[
"In dieser Wüste hier\nFind't nirgend meine Seele Ruh',\nDenn meine Ruh' bist, Jesu, Du.\nWohl mir, ich geh' zu Dir!\nBald werd' ich bei Dir sein,\nBald mit den Deinen ewiglich\nAnbeten, loben, preisen Dich,\nMich Deiner stets erfreun.\n",
"v3"
]
]
}

View File

@ -0,0 +1,30 @@
SONGNR,TITLE,AUTHOR,COPYRIGHT,FIRSTLINE,PRIKEY,ALTKEY,TEMPO,FOCUS,THEME,SCRIPTURE,ACTIVE,SONGBOOK,TIMESIG,INTRODUCED,LASTUSED,TIMESUSED,CCLINR,USER1,USER2,USER3,USER4,USER5,ROADMAP,FILELINK1,OVERMAP,FILELINK2,LYRICS,INFO,LYRICS2,Background
"7","Would You Be Free","Jones, Lewis E.","Public Domain","Would you be free from your burden of sin?","G","","Moderate","Only To Others","","","N","Y","","1899-12-30","1899-12-30","","","","","","","","1,C,1","","","",".G C G
Would you be free from your burden of sin?
. D D7 G
There's power in the blood, power in the blood
. C G
Would you o'er evil a victory win?
. D D7 G
There's wonderful power in the blood
.G C G
There is power, power, wonder working power
.D G
In the blood of the Lamb
. C G
There is power, power, wonder working power
. D G
In the precious blood of the Lamb
","","[1]
Would you be free from your burden of sin?
There's power in the blood, power in the blood
Would you o'er evil a victory win?
There's wonderful power in the blood
[C]
There is power, power, wonder working power
In the blood of the Lamb
There is power, power, wonder working power
In the precious blood of the Lamb
",""
1 SONGNR TITLE AUTHOR COPYRIGHT FIRSTLINE PRIKEY ALTKEY TEMPO FOCUS THEME SCRIPTURE ACTIVE SONGBOOK TIMESIG INTRODUCED LASTUSED TIMESUSED CCLINR USER1 USER2 USER3 USER4 USER5 ROADMAP FILELINK1 OVERMAP FILELINK2 LYRICS INFO LYRICS2 Background
2 7 Would You Be Free Jones, Lewis E. Public Domain Would you be free from your burden of sin? G Moderate Only To Others N Y 1899-12-30 1899-12-30 1,C,1 .G C G Would you be free from your burden of sin? . D D7 G There's power in the blood, power in the blood . C G Would you o'er evil a victory win? . D D7 G There's wonderful power in the blood .G C G There is power, power, wonder working power .D G In the blood of the Lamb . C G There is power, power, wonder working power . D G In the precious blood of the Lamb [1] Would you be free from your burden of sin? There's power in the blood, power in the blood Would you o'er evil a victory win? There's wonderful power in the blood [C] There is power, power, wonder working power In the blood of the Lamb There is power, power, wonder working power In the precious blood of the Lamb

View File

@ -0,0 +1,19 @@
{
"authors": [
"Jones",
"Lewis E"
],
"title": "Would You Be Free",
"verse_order_list": ["v1", "c1", "v1"],
"copyright": "Public Domain",
"verses": [
[
"Would you be free from your burden of sin? \nThere's power in the blood, power in the blood \nWould you o'er evil a victory win? \nThere's wonderful power in the blood \n",
"v1"
],
[
"There is power, power, wonder working power \nIn the blood of the Lamb \nThere is power, power, wonder working power \nIn the precious blood of the Lamb \n",
"c1"
]
]
}

View File

@ -50,10 +50,6 @@ TAGS = [
['1.9.11', '2039'], ['1.9.11', '2039'],
['1.9.12', '2063'], ['1.9.12', '2063'],
['2.0', '2118'], ['2.0', '2118'],
['2.0.1', '?'],
['2.0.2', '?'],
['2.0.3', '?'],
['2.0.4', '?'],
['2.1.0', '2119'] ['2.1.0', '2119']
] ]