forked from openlp/openlp
head
This commit is contained in:
commit
89cbe8bc7d
@ -110,7 +110,7 @@ class AppLocation(object):
|
||||
:param extension:
|
||||
Defaults to *None*. The extension to search for. For example::
|
||||
|
||||
u'.png'
|
||||
'.png'
|
||||
"""
|
||||
path = AppLocation.get_data_path()
|
||||
if section:
|
||||
|
@ -68,8 +68,7 @@ class Settings(QtCore.QSettings):
|
||||
``__obsolete_settings__``
|
||||
Each entry is structured in the following way::
|
||||
|
||||
(u'general/enable slide loop', u'advanced/slide limits',
|
||||
[(SlideLimits.Wrap, True), (SlideLimits.End, False)])
|
||||
('general/enable slide loop', 'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)])
|
||||
|
||||
The first entry is the *old key*; it will be removed.
|
||||
|
||||
|
@ -296,8 +296,7 @@ def create_separated_list(string_list):
|
||||
|
||||
:param string_list: List of unicode strings
|
||||
"""
|
||||
if LooseVersion(Qt.PYQT_VERSION_STR) >= LooseVersion('4.9') and \
|
||||
LooseVersion(Qt.qVersion()) >= LooseVersion('4.8'):
|
||||
if LooseVersion(Qt.PYQT_VERSION_STR) >= LooseVersion('4.9') and LooseVersion(Qt.qVersion()) >= LooseVersion('4.8'):
|
||||
return QtCore.QLocale().createSeparatedList(string_list)
|
||||
if not string_list:
|
||||
return ''
|
||||
|
@ -129,7 +129,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
|
||||
|
||||
class MyPlugin(Plugin):
|
||||
def __init__(self):
|
||||
super(MyPlugin, self).__init__('MyPlugin', version=u'0.1')
|
||||
super(MyPlugin, self).__init__('MyPlugin', version='0.1')
|
||||
|
||||
:param name: Defaults to *None*. The name of the plugin.
|
||||
:param default_settings: A dict containing the plugin's settings. The value to each key is the default value
|
||||
|
@ -248,6 +248,9 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
||||
elif item.is_capable(ItemCapabilities.CanSoftBreak):
|
||||
pages = []
|
||||
if '[---]' in text:
|
||||
# Remove two or more option slide breaks next to each other (causing infinite loop).
|
||||
while '\n[---]\n[---]\n' in text:
|
||||
text = text.replace('\n[---]\n[---]\n', '\n[---]\n')
|
||||
while True:
|
||||
slides = text.split('\n[---]\n', 2)
|
||||
# If there are (at least) two occurrences of [---] we use the first two slides (and neglect the last
|
||||
@ -392,7 +395,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
||||
off when displayed.
|
||||
|
||||
:param lines: The text to be fitted on the slide split into lines.
|
||||
:param line_end: The text added after each line. Either ``u' '`` or ``u'<br>``.
|
||||
:param line_end: The text added after each line. Either ``' '`` or ``'<br>``.
|
||||
"""
|
||||
formatted = []
|
||||
previous_html = ''
|
||||
@ -416,7 +419,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
||||
processed word by word. This is sometimes need for **bible** verses.
|
||||
|
||||
:param lines: The text to be fitted on the slide split into lines.
|
||||
:param line_end: The text added after each line. Either ``u' '`` or ``u'<br>``. This is needed for **bibles**.
|
||||
:param line_end: The text added after each line. Either ``' '`` or ``'<br>``. This is needed for **bibles**.
|
||||
"""
|
||||
formatted = []
|
||||
previous_html = ''
|
||||
@ -453,7 +456,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
||||
"""
|
||||
Tests the given text for not closed formatting tags and returns a tuple consisting of three unicode strings::
|
||||
|
||||
(u'{st}{r}Text text text{/r}{/st}', u'{st}{r}', u'<strong><span style="-webkit-text-fill-color:red">')
|
||||
('{st}{r}Text text text{/r}{/st}', '{st}{r}', '<strong><span style="-webkit-text-fill-color:red">')
|
||||
|
||||
The first unicode string is the text, with correct closing tags. The second unicode string are OpenLP's opening
|
||||
formatting tags and the third unicode string the html opening formatting tags.
|
||||
@ -500,8 +503,8 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
||||
The text contains html.
|
||||
:param raw_list: The elements which do not fit on a slide and needs to be processed using the binary chop.
|
||||
The elements can contain formatting tags.
|
||||
:param separator: The separator for the elements. For lines this is ``u'<br>'`` and for words this is ``u' '``.
|
||||
:param line_end: The text added after each "element line". Either ``u' '`` or ``u'<br>``. This is needed for
|
||||
:param separator: The separator for the elements. For lines this is ``'<br>'`` and for words this is ``' '``.
|
||||
:param line_end: The text added after each "element line". Either ``' '`` or ``'<br>``. This is needed for
|
||||
bibles.
|
||||
"""
|
||||
smallest_index = 0
|
||||
|
@ -63,8 +63,7 @@ class ScreenList(object):
|
||||
"""
|
||||
Initialise the screen list.
|
||||
|
||||
``desktop``
|
||||
A ``QDesktopWidget`` object.
|
||||
:param desktop: A QDesktopWidget object.
|
||||
"""
|
||||
screen_list = cls()
|
||||
screen_list.desktop = desktop
|
||||
@ -136,7 +135,7 @@ class ScreenList(object):
|
||||
Returns a list with the screens. This should only be used to display
|
||||
available screens to the user::
|
||||
|
||||
[u'Screen 1 (primary)', u'Screen 2']
|
||||
['Screen 1 (primary)', 'Screen 2']
|
||||
"""
|
||||
screen_list = []
|
||||
for screen in self.screen_list:
|
||||
@ -153,9 +152,9 @@ class ScreenList(object):
|
||||
:param screen: A dict with the screen properties::
|
||||
|
||||
{
|
||||
u'primary': True,
|
||||
u'number': 0,
|
||||
u'size': PyQt4.QtCore.QRect(0, 0, 1024, 768)
|
||||
'primary': True,
|
||||
'number': 0,
|
||||
'size': PyQt4.QtCore.QRect(0, 0, 1024, 768)
|
||||
}
|
||||
"""
|
||||
log.info('Screen %d found with resolution %s' % (screen['number'], screen['size']))
|
||||
|
@ -30,7 +30,7 @@
|
||||
The About dialog.
|
||||
"""
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from .aboutdialog import Ui_AboutDialog
|
||||
from openlp.core.lib import translate
|
||||
|
@ -30,7 +30,7 @@
|
||||
The GUI widgets of the exception dialog.
|
||||
"""
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from openlp.core.lib import translate
|
||||
from openlp.core.lib.ui import create_button, create_button_box
|
||||
|
@ -199,8 +199,8 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
self.no_internet_label.setText(self.no_internet_text + self.cancelWizardText)
|
||||
elif page_id == FirstTimePage.Defaults:
|
||||
self.theme_combo_box.clear()
|
||||
for iter in range(self.themes_list_widget.count()):
|
||||
item = self.themes_list_widget.item(iter)
|
||||
for index in range(self.themes_list_widget.count()):
|
||||
item = self.themes_list_widget.item(index)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
self.theme_combo_box.addItem(item.text())
|
||||
if self.has_run_wizard:
|
||||
@ -292,13 +292,9 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
"""
|
||||
themes = self.config.get('themes', 'files')
|
||||
themes = themes.split(',')
|
||||
for theme in themes:
|
||||
filename = self.config.get('theme_%s' % theme, 'filename')
|
||||
for index, theme in enumerate(themes):
|
||||
screenshot = self.config.get('theme_%s' % theme, 'screenshot')
|
||||
for index in range(self.themes_list_widget.count()):
|
||||
item = self.themes_list_widget.item(index)
|
||||
if item.data(QtCore.Qt.UserRole) == filename:
|
||||
break
|
||||
item.setIcon(build_icon(os.path.join(gettempdir(), 'openlp', screenshot)))
|
||||
|
||||
def _get_file_size(self, url):
|
||||
|
@ -1334,7 +1334,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
if self.copy_data:
|
||||
log.info('Copying data to new path')
|
||||
try:
|
||||
self.showStatusMessage(
|
||||
self.show_status_message(
|
||||
translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - %s '
|
||||
'- Please wait for copy to finish').replace('%s', self.new_data_path))
|
||||
dir_util.copy_tree(old_data_path, self.new_data_path)
|
||||
@ -1364,8 +1364,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
args = []
|
||||
for a in self.arguments:
|
||||
args.extend([a])
|
||||
for arg in args:
|
||||
filename = arg
|
||||
for filename in args:
|
||||
if not isinstance(filename, str):
|
||||
filename = str(filename, sys.getfilesystemencoding())
|
||||
if filename.endswith(('.osz', '.oszl')):
|
||||
|
@ -29,8 +29,6 @@
|
||||
"""
|
||||
The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class.
|
||||
"""
|
||||
import os
|
||||
|
||||
from openlp.core.common import RegistryProperties
|
||||
from openlp.core.ui.media import MediaState
|
||||
|
||||
|
@ -33,10 +33,8 @@ import logging
|
||||
import mimetypes
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
from openlp.core.common import Settings
|
||||
from openlp.core.lib import translate
|
||||
|
||||
from openlp.core.ui.media import MediaState
|
||||
|
@ -242,7 +242,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog, RegistryProperties)
|
||||
Creates a html element. If ``text`` is given, the element's text will set and if a ``parent`` is given,
|
||||
the element is appended.
|
||||
|
||||
:param tag: The html tag, e. g. ``u'span'``. Defaults to ``None``.
|
||||
:param tag: The html tag, e. g. ``'span'``. Defaults to ``None``.
|
||||
:param text: The text for the tag. Defaults to ``None``.
|
||||
:param parent: The parent element. Defaults to ``None``.
|
||||
:param classId: Value for the class attribute
|
||||
|
@ -244,10 +244,10 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog, RegistryProperties)
|
||||
self.primary_push_button.setChecked(False)
|
||||
self.alternate_push_button.setChecked(False)
|
||||
else:
|
||||
if action.defaultShortcuts:
|
||||
primary_label_text = action.defaultShortcuts[0].toString()
|
||||
if len(action.defaultShortcuts) == 2:
|
||||
alternate_label_text = action.defaultShortcuts[1].toString()
|
||||
if action.default_shortcuts:
|
||||
primary_label_text = action.default_shortcuts[0].toString()
|
||||
if len(action.default_shortcuts) == 2:
|
||||
alternate_label_text = action.default_shortcuts[1].toString()
|
||||
shortcuts = self._action_shortcuts(action)
|
||||
# We do not want to loose pending changes, that is why we have to keep the text when, this function has not
|
||||
# been triggered by a signal.
|
||||
@ -292,7 +292,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog, RegistryProperties)
|
||||
self._adjust_button(self.alternate_push_button, False, text='')
|
||||
for category in self.action_list.categories:
|
||||
for action in category.actions:
|
||||
self.changed_actions[action] = action.defaultShortcuts
|
||||
self.changed_actions[action] = action.default_shortcuts
|
||||
self.refresh_shortcut_list()
|
||||
|
||||
def on_default_radio_button_clicked(self, toggled):
|
||||
@ -306,7 +306,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog, RegistryProperties)
|
||||
if action is None:
|
||||
return
|
||||
temp_shortcuts = self._action_shortcuts(action)
|
||||
self.changed_actions[action] = action.defaultShortcuts
|
||||
self.changed_actions[action] = action.default_shortcuts
|
||||
self.refresh_shortcut_list()
|
||||
primary_button_text = ''
|
||||
alternate_button_text = ''
|
||||
@ -357,8 +357,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog, RegistryProperties)
|
||||
return
|
||||
shortcuts = self._action_shortcuts(action)
|
||||
new_shortcuts = []
|
||||
if action.defaultShortcuts:
|
||||
new_shortcuts.append(action.defaultShortcuts[0])
|
||||
if action.default_shortcuts:
|
||||
new_shortcuts.append(action.default_shortcuts[0])
|
||||
# We have to check if the primary default shortcut is available. But we only have to check, if the action
|
||||
# has a default primary shortcut (an "empty" shortcut is always valid and if the action does not have a
|
||||
# default primary shortcut, then the alternative shortcut (not the default one) will become primary
|
||||
@ -383,8 +383,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog, RegistryProperties)
|
||||
new_shortcuts = []
|
||||
if shortcuts:
|
||||
new_shortcuts.append(shortcuts[0])
|
||||
if len(action.defaultShortcuts) == 2:
|
||||
new_shortcuts.append(action.defaultShortcuts[1])
|
||||
if len(action.default_shortcuts) == 2:
|
||||
new_shortcuts.append(action.default_shortcuts[1])
|
||||
if len(new_shortcuts) == 2:
|
||||
if not self._validiate_shortcut(action, new_shortcuts[1]):
|
||||
return
|
||||
|
@ -190,7 +190,7 @@ class ThemesTab(SettingsTab):
|
||||
|
||||
:param theme_list: The list of available themes::
|
||||
|
||||
[u'Bible Theme', u'Song Theme']
|
||||
['Bible Theme', 'Song Theme']
|
||||
"""
|
||||
# Reload as may have been triggered by the ThemeManager.
|
||||
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
||||
|
@ -279,7 +279,7 @@ class OpenLPWizard(QtGui.QWizard, RegistryProperties):
|
||||
:param filters: The file extension filters. It should contain the file description
|
||||
as well as the file extension. For example::
|
||||
|
||||
u'OpenLP 2.0 Databases (*.sqlite)'
|
||||
'OpenLP 2.0 Databases (*.sqlite)'
|
||||
"""
|
||||
if filters:
|
||||
filters += ';;'
|
||||
|
@ -113,7 +113,7 @@ def get_application_version():
|
||||
"""
|
||||
Returns the application version of the running instance of OpenLP::
|
||||
|
||||
{u'full': u'1.9.4-bzr1249', u'version': u'1.9.4', u'build': u'bzr1249'}
|
||||
{'full': '1.9.4-bzr1249', 'version': '1.9.4', 'build': 'bzr1249'}
|
||||
"""
|
||||
global APPLICATION_VERSION
|
||||
if APPLICATION_VERSION:
|
||||
|
@ -65,20 +65,14 @@ class CategoryActionList(object):
|
||||
self.index = 0
|
||||
self.actions = []
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
Implement the __getitem__() method to make this class a dictionary type
|
||||
"""
|
||||
for weight, action in self.actions:
|
||||
if action.text() == key:
|
||||
return action
|
||||
raise KeyError('Action "%s" does not exist.' % key)
|
||||
|
||||
def __contains__(self, item):
|
||||
def __contains__(self, key):
|
||||
"""
|
||||
Implement the __contains__() method to make this class a dictionary type
|
||||
"""
|
||||
return item in self
|
||||
for weight, action in self.actions:
|
||||
if action == key:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
@ -103,23 +97,14 @@ class CategoryActionList(object):
|
||||
self.index += 1
|
||||
return self.actions[self.index - 1][1]
|
||||
|
||||
def has_key(self, key):
|
||||
"""
|
||||
Implement the has_key() method to make this class a dictionary type
|
||||
"""
|
||||
for weight, action in self.actions:
|
||||
if action.text() == key:
|
||||
return True
|
||||
return False
|
||||
|
||||
def append(self, name):
|
||||
def append(self, action):
|
||||
"""
|
||||
Append an action
|
||||
"""
|
||||
weight = 0
|
||||
if self.actions:
|
||||
weight = self.actions[-1][0] + 1
|
||||
self.add(name, weight)
|
||||
self.add(action, weight)
|
||||
|
||||
def add(self, action, weight=0):
|
||||
"""
|
||||
@ -128,14 +113,15 @@ class CategoryActionList(object):
|
||||
self.actions.append((weight, action))
|
||||
self.actions.sort(key=lambda act: act[0])
|
||||
|
||||
def remove(self, remove_action):
|
||||
def remove(self, action):
|
||||
"""
|
||||
Remove an action
|
||||
"""
|
||||
for action in self.actions:
|
||||
if action[1] == remove_action:
|
||||
self.actions.remove(action)
|
||||
for item in self.actions:
|
||||
if item[1] == action:
|
||||
self.actions.remove(item)
|
||||
return
|
||||
raise ValueError('Action "%s" does not exist.' % action)
|
||||
|
||||
|
||||
class CategoryList(object):
|
||||
@ -184,9 +170,9 @@ class CategoryList(object):
|
||||
self.index += 1
|
||||
return self.categories[self.index - 1]
|
||||
|
||||
def has_key(self, key):
|
||||
def __contains__(self, key):
|
||||
"""
|
||||
Implement the has_key() method to make this class like a dictionary
|
||||
Implement the __contains__() method to make this class like a dictionary
|
||||
"""
|
||||
for category in self.categories:
|
||||
if category.name == key:
|
||||
@ -200,10 +186,7 @@ class CategoryList(object):
|
||||
weight = 0
|
||||
if self.categories:
|
||||
weight = self.categories[-1].weight + 1
|
||||
if actions:
|
||||
self.add(name, weight, actions)
|
||||
else:
|
||||
self.add(name, weight)
|
||||
|
||||
def add(self, name, weight=0, actions=None):
|
||||
"""
|
||||
@ -226,6 +209,8 @@ class CategoryList(object):
|
||||
for category in self.categories:
|
||||
if category.name == name:
|
||||
self.categories.remove(category)
|
||||
return
|
||||
raise ValueError('Category "%s" does not exist.' % name)
|
||||
|
||||
|
||||
class ActionList(object):
|
||||
@ -270,7 +255,7 @@ class ActionList(object):
|
||||
settings = Settings()
|
||||
settings.beginGroup('shortcuts')
|
||||
# Get the default shortcut from the config.
|
||||
action.defaultShortcuts = settings.get_default_value(action.objectName())
|
||||
action.default_shortcuts = settings.get_default_value(action.objectName())
|
||||
if weight is None:
|
||||
self.categories[category].actions.append(action)
|
||||
else:
|
||||
|
@ -32,7 +32,7 @@ other class holds all the functional code, like slots and loading and saving.
|
||||
|
||||
The first class, commonly known as the **Dialog** class, is typically named ``Ui_<name>Dialog``. It is a slightly
|
||||
modified version of the class that the ``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||
converting most strings from "" to u'' and using OpenLP's ``translate()`` function for translating strings.
|
||||
converting most strings from "" to '' and using OpenLP's ``translate()`` function for translating strings.
|
||||
|
||||
The second class, commonly known as the **Form** class, is typically named ``<name>Form``. This class is the one which
|
||||
is instantiated and used. It uses dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class mentioned
|
||||
|
@ -33,7 +33,7 @@ other class holds all the functional code, like slots and loading and saving.
|
||||
|
||||
The first class, commonly known as the **Dialog** class, is typically named ``Ui_<name>Dialog``. It is a slightly
|
||||
modified version of the class that the ``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||
converting most strings from "" to u'' and using OpenLP's ``translate()`` function for translating strings.
|
||||
converting most strings from "" to '' and using OpenLP's ``translate()`` function for translating strings.
|
||||
|
||||
The second class, commonly known as the **Form** class, is typically named ``<name>Form``. This class is the one which
|
||||
is instantiated and used. It uses dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class mentioned
|
||||
|
@ -262,7 +262,7 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||
|
||||
For example::
|
||||
|
||||
[(u'John', 3, 16, 18), (u'John', 4, 1, 1)]
|
||||
[('John', 3, 16, 18), ('John', 4, 1, 1)]
|
||||
|
||||
**Reference string details:**
|
||||
|
||||
@ -311,7 +311,7 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||
``(?P<to_verse>[0-9]+)``
|
||||
The ``to_verse`` reference is equivalent to group 2.
|
||||
|
||||
The full reference is matched against get_reference_match(u'full'). This regular expression looks like this:
|
||||
The full reference is matched against get_reference_match('full'). This regular expression looks like this:
|
||||
|
||||
``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
|
||||
The ``book`` group starts with the first non-whitespace character. There are optional leading digits followed by
|
||||
|
@ -405,7 +405,7 @@ class BiblesTab(SettingsTab):
|
||||
:param theme_list:
|
||||
The list of available themes::
|
||||
|
||||
[u'Bible Theme', u'Song Theme']
|
||||
['Bible Theme', 'Song Theme']
|
||||
"""
|
||||
self.bible_theme_combo_box.clear()
|
||||
self.bible_theme_combo_box.addItem('')
|
||||
|
@ -370,17 +370,16 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
This is probably the most used function. It retrieves the list of
|
||||
verses based on the user's query.
|
||||
|
||||
:param reference_list: This is the list of references the media manager item wants. It is
|
||||
a list of tuples, with the following format::
|
||||
:param reference_list: This is the list of references the media manager item wants. It is a list of tuples, with
|
||||
the following format::
|
||||
|
||||
(book_reference_id, chapter, start_verse, end_verse)
|
||||
|
||||
Therefore, when you are looking for multiple items, simply break
|
||||
them up into references like this, bundle them into a list. This
|
||||
function then runs through the list, and returns an amalgamated
|
||||
list of ``Verse`` objects. For example::
|
||||
Therefore, when you are looking for multiple items, simply break them up into references like this, bundle
|
||||
them into a list. This function then runs through the list, and returns an amalgamated list of ``Verse``
|
||||
objects. For example::
|
||||
|
||||
[(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
|
||||
[('35', 1, 1, 1), ('35', 2, 2, 3)]
|
||||
:param show_error:
|
||||
"""
|
||||
log.debug('BibleDB.get_verses("%s")' % reference_list)
|
||||
|
@ -534,7 +534,7 @@ class HTTPBible(BibleDB, RegistryProperties):
|
||||
them into a list. This function then runs through the list, and returns an amalgamated list of ``Verse``
|
||||
objects. For example::
|
||||
|
||||
[(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
|
||||
[('35', 1, 1, 1), ('35', 2, 2, 3)]
|
||||
"""
|
||||
log.debug('HTTPBible.get_verses("%s")', reference_list)
|
||||
for reference in reference_list:
|
||||
|
@ -54,19 +54,19 @@ class BibleFormat(object):
|
||||
WebDownload = 3
|
||||
|
||||
@staticmethod
|
||||
def get_class(format):
|
||||
def get_class(bible_format):
|
||||
"""
|
||||
Return the appropriate implementation class.
|
||||
|
||||
:param format: The Bible format.
|
||||
:param bible_format: The Bible format.
|
||||
"""
|
||||
if format == BibleFormat.OSIS:
|
||||
if bible_format == BibleFormat.OSIS:
|
||||
return OSISBible
|
||||
elif format == BibleFormat.CSV:
|
||||
elif bible_format == BibleFormat.CSV:
|
||||
return CSVBible
|
||||
elif format == BibleFormat.OpenSong:
|
||||
elif bible_format == BibleFormat.OpenSong:
|
||||
return OpenSongBible
|
||||
elif format == BibleFormat.WebDownload:
|
||||
elif bible_format == BibleFormat.WebDownload:
|
||||
return HTTPBible
|
||||
else:
|
||||
return None
|
||||
|
@ -360,8 +360,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
combo boxes on the 'Advanced Search' Tab. This is not of any importance of the 'Quick Search' Tab.
|
||||
|
||||
:param bible: The bible to initialise (unicode).
|
||||
:param last_book_id: The "book reference id" of the book which is chosen at the moment.
|
||||
(int)
|
||||
:param last_book_id: The "book reference id" of the book which is chosen at the moment. (int)
|
||||
"""
|
||||
log.debug('initialise_advanced_bible %s, %s', bible, last_book_id)
|
||||
book_data = self.plugin.manager.get_books(bible)
|
||||
@ -421,9 +420,8 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def update_auto_completer(self):
|
||||
"""
|
||||
This updates the bible book completion list for the search field. The
|
||||
completion depends on the bible. It is only updated when we are doing a
|
||||
reference search, otherwise the auto completion list is removed.
|
||||
This updates the bible book completion list for the search field. The completion depends on the bible. It is
|
||||
only updated when we are doing a reference search, otherwise the auto completion list is removed.
|
||||
"""
|
||||
log.debug('update_auto_completer')
|
||||
# Save the current search type to the configuration.
|
||||
@ -593,8 +591,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
:param range_from: The first number of the range (int).
|
||||
:param range_to: The last number of the range (int).
|
||||
:param combo: The combo box itself (QComboBox).
|
||||
:param restore: If True, then the combo's currentText will be restored after
|
||||
adjusting (if possible).
|
||||
:param restore: If True, then the combo's currentText will be restored after adjusting (if possible).
|
||||
"""
|
||||
log.debug('adjust_combo_box %s, %s, %s', combo, range_from, range_to)
|
||||
if restore:
|
||||
@ -640,8 +637,8 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def on_quick_search_button(self):
|
||||
"""
|
||||
Does a quick search and saves the search results. Quick search can
|
||||
either be "Reference Search" or "Text Search".
|
||||
Does a quick search and saves the search results. Quick search can either be "Reference Search" or
|
||||
"Text Search".
|
||||
"""
|
||||
log.debug('Quick Search Button clicked')
|
||||
self.quickSearchButton.setEnabled(False)
|
||||
@ -696,8 +693,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def display_results(self, bible, second_bible=''):
|
||||
"""
|
||||
Displays the search results in the media manager. All data needed for
|
||||
further action is saved for/in each row.
|
||||
Displays the search results in the media manager. All data needed for further action is saved for/in each row.
|
||||
"""
|
||||
items = self.build_display_results(bible, second_bible, self.search_results)
|
||||
for bible_verse in items:
|
||||
@ -708,8 +704,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def build_display_results(self, bible, second_bible, search_results):
|
||||
"""
|
||||
Displays the search results in the media manager. All data needed for
|
||||
further action is saved for/in each row.
|
||||
Displays the search results in the media manager. All data needed for further action is saved for/in each row.
|
||||
"""
|
||||
verse_separator = get_reference_separator('sep_v_display')
|
||||
version = self.plugin.manager.get_meta_data(bible, 'name').value
|
||||
@ -837,7 +832,6 @@ class BibleMediaItem(MediaManagerItem):
|
||||
# If there are no more items we check whether we have to add bible_text.
|
||||
if bible_text:
|
||||
raw_slides.append(bible_text.lstrip())
|
||||
bible_text = ''
|
||||
# Service Item: Capabilities
|
||||
if self.settings.layout_style == LayoutStyle.Continuous and not second_bible:
|
||||
# Split the line but do not replace line breaks in renderer.
|
||||
@ -859,9 +853,8 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def format_title(self, start_bitem, old_bitem):
|
||||
"""
|
||||
This method is called, when we have to change the title, because
|
||||
we are at the end of a verse range. E. g. if we want to add
|
||||
Genesis 1:1-6 as well as Daniel 2:14.
|
||||
This method is called, when we have to change the title, because we are at the end of a verse range. E. g. if we
|
||||
want to add Genesis 1:1-6 as well as Daniel 2:14.
|
||||
|
||||
:param start_bitem: The first item of a range.
|
||||
:param old_bitem: The last item of a range.
|
||||
@ -891,10 +884,8 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def check_title(self, bitem, old_bitem):
|
||||
"""
|
||||
This method checks if we are at the end of an verse range. If that is
|
||||
the case, we return True, otherwise False. E. g. if we added
|
||||
|
||||
Genesis 1:1-6, but the next verse is Daniel 2:14, we return True.
|
||||
This method checks if we are at the end of an verse range. If that is the case, we return True, otherwise False.
|
||||
E. g. if we added Genesis 1:1-6, but the next verse is Daniel 2:14, we return True.
|
||||
|
||||
:param bitem: The item we are dealing with at the moment.
|
||||
:param old_bitem: The item we were previously dealing with.
|
||||
@ -918,20 +909,17 @@ class BibleMediaItem(MediaManagerItem):
|
||||
return True
|
||||
elif old_chapter + 1 == chapter and (verse != 1 or old_verse !=
|
||||
self.plugin.manager.get_verse_count(old_bible, old_book, old_chapter)):
|
||||
# We are in the following chapter, but the last verse was not the
|
||||
# last verse of the chapter or the current verse is not the
|
||||
# first one of the chapter.
|
||||
# We are in the following chapter, but the last verse was not the last verse of the chapter or the current
|
||||
# verse is not the first one of the chapter.
|
||||
return True
|
||||
return False
|
||||
|
||||
def format_verse(self, old_chapter, chapter, verse):
|
||||
"""
|
||||
Formats and returns the text, each verse starts with, for the given
|
||||
chapter and verse. The text is either surrounded by round, square,
|
||||
Formats and returns the text, each verse starts with, for the given chapter and verse. The text is either
|
||||
surrounded by round, square, curly brackets or no brackets at all. For example::
|
||||
|
||||
curly brackets or no brackets at all. For example::
|
||||
|
||||
u'{su}1:1{/su}'
|
||||
'{su}1:1{/su}'
|
||||
|
||||
:param old_chapter: The previous verse's chapter number (int).
|
||||
:param chapter: The chapter number (int).
|
||||
|
@ -197,7 +197,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
self.slide_list_view.clear()
|
||||
self.slide_list_view.addItems(slides)
|
||||
else:
|
||||
old_slides = []
|
||||
old_row = self.slide_list_view.currentRow()
|
||||
# Create a list with all (old/unedited) slides.
|
||||
old_slides = [self.slide_list_view.item(row).text() for row in range(self.slide_list_view.count())]
|
||||
|
@ -32,7 +32,7 @@ other class holds all the functional code, like slots and loading and saving.
|
||||
|
||||
The first class, commonly known as the **Dialog** class, is typically named ``Ui_<name>Dialog``. It is a slightly
|
||||
modified version of the class that the ``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||
converting most strings from "" to u'' and using OpenLP's ``translate()`` function for translating strings.
|
||||
converting most strings from "" to '' and using OpenLP's ``translate()`` function for translating strings.
|
||||
|
||||
The second class, commonly known as the **Form** class, is typically named ``<name>Form``. This class is the one which
|
||||
is instantiated and used. It uses dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class mentioned
|
||||
|
@ -31,7 +31,7 @@ The :mod:`db` module provides the database and schema that is the backend for th
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Table, types
|
||||
from sqlalchemy.orm import mapper, relation, reconstructor
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from openlp.core.lib.db import BaseModel, init_db
|
||||
|
||||
|
@ -314,7 +314,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
||||
def get_list(self, type=MediaType.Audio):
|
||||
media = Settings().value(self.settings_section + '/media files')
|
||||
media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1]))
|
||||
extension = []
|
||||
if type == MediaType.Audio:
|
||||
extension = self.media_controller.audio_extensions_list
|
||||
else:
|
||||
|
@ -354,7 +354,7 @@ class PresentationController(object):
|
||||
class MyPresentationController(PresentationController):
|
||||
def __init__(self, plugin):
|
||||
PresentationController.__init(
|
||||
self, plugin, u'My Presenter App')
|
||||
self, plugin, 'My Presenter App')
|
||||
|
||||
:param plugin: Defaults to *None*. The presentationplugin object
|
||||
:param name: Name of the application, to appear in the application
|
||||
|
@ -34,7 +34,7 @@ code, like slots and loading and saving.
|
||||
The first class, commonly known as the **Dialog** class, is typically named
|
||||
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
|
||||
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||
converting most strings from "" to u'' and using OpenLP's ``translate()``
|
||||
converting most strings from "" to '' and using OpenLP's ``translate()``
|
||||
function for translating strings.
|
||||
|
||||
The second class, commonly known as the **Form** class, is typically named
|
||||
|
@ -122,8 +122,6 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
||||
text = text[:position + 4]
|
||||
match = VERSE_REGEX.match(text)
|
||||
if match:
|
||||
# TODO: Not used, remove?
|
||||
# verse_tag = match.group(1)
|
||||
try:
|
||||
verse_num = int(match.group(2)) + 1
|
||||
except ValueError:
|
||||
|
@ -231,11 +231,11 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
|
||||
"""
|
||||
Opens a QFileDialog and writes the filenames to the given listbox.
|
||||
|
||||
:param title: The title of the dialog (unicode).
|
||||
:param title: The title of the dialog (str).
|
||||
:param listbox: A listbox (QListWidget).
|
||||
:param filters: The file extension filters. It should contain the file descriptions
|
||||
as well as the file extensions. For example::
|
||||
u'SongBeamer Files (*.sng)'
|
||||
:param filters: The file extension filters. It should contain the file descriptions as well as the file
|
||||
extensions. For example::
|
||||
'SongBeamer Files (*.sng)'
|
||||
"""
|
||||
if filters:
|
||||
filters += ';;'
|
||||
|
@ -319,8 +319,6 @@ class SongSelectForm(QtGui.QDialog, Ui_SongSelectDialog):
|
||||
def on_search_finished(self):
|
||||
"""
|
||||
Slot which is called when the search is completed.
|
||||
|
||||
:param songs:
|
||||
"""
|
||||
self.application.process_events()
|
||||
self.search_progress_bar.setVisible(False)
|
||||
|
@ -434,7 +434,7 @@ def strip_rtf(text, default_encoding=None):
|
||||
# Current font is the font tag we last met.
|
||||
font = ''
|
||||
# Character encoding is defined inside fonttable.
|
||||
# font_table could contain eg u'0': u'cp1252'
|
||||
# font_table could contain eg '0': u'cp1252'
|
||||
font_table = {'': ''}
|
||||
# Stack of things to keep track of when entering/leaving groups.
|
||||
stack = []
|
||||
|
@ -292,7 +292,7 @@ class EasySlidesImport(SongImport):
|
||||
return True
|
||||
|
||||
def _extract_region(self, line):
|
||||
# this was true already: line[0:7] == u'[region':
|
||||
# this was true already: line[0:7] == '[region':
|
||||
"""
|
||||
Extract the region from text
|
||||
|
||||
|
@ -34,13 +34,13 @@ EasyWorship song databases into the current installation database.
|
||||
import os
|
||||
import struct
|
||||
import re
|
||||
import zlib
|
||||
|
||||
from openlp.core.lib import translate
|
||||
from openlp.plugins.songs.lib import VerseType
|
||||
from openlp.plugins.songs.lib import retrieve_windows_encoding, strip_rtf
|
||||
from .songimport import SongImport
|
||||
|
||||
RTF_STRIPPING_REGEX = re.compile(r'\{\\tx[^}]*\}')
|
||||
# regex: at least two newlines, can have spaces between them
|
||||
SLIDE_BREAK_REGEX = re.compile(r'\n *?\n[\n ]*')
|
||||
NUMBER_REGEX = re.compile(r'[0-9]+')
|
||||
@ -77,9 +77,121 @@ class EasyWorshipSongImport(SongImport):
|
||||
|
||||
def do_import(self):
|
||||
"""
|
||||
Import the songs
|
||||
Determines the type of file to import and calls the appropiate method
|
||||
"""
|
||||
if self.import_source.lower().endswith('ews'):
|
||||
self.import_ews()
|
||||
else:
|
||||
self.import_db()
|
||||
|
||||
:return:
|
||||
def import_ews(self):
|
||||
"""
|
||||
Import the songs from service file
|
||||
The full spec of the ews files can be found here:
|
||||
https://github.com/meinders/lithium-ews/blob/master/docs/ews%20file%20format.md
|
||||
or here: http://wiki.openlp.org/Development:EasyWorship_EWS_Format
|
||||
"""
|
||||
# Open ews file if it exists
|
||||
if not os.path.isfile(self.import_source):
|
||||
log.debug('Given ews file does not exists.')
|
||||
return
|
||||
# Make sure there is room for at least a header and one entry
|
||||
if os.path.getsize(self.import_source) < 892:
|
||||
log.debug('Given ews file is to small to contain valid data.')
|
||||
return
|
||||
# Take a stab at how text is encoded
|
||||
self.encoding = 'cp1252'
|
||||
self.encoding = retrieve_windows_encoding(self.encoding)
|
||||
if not self.encoding:
|
||||
log.debug('No encoding set.')
|
||||
return
|
||||
self.ews_file = open(self.import_source, 'rb')
|
||||
# EWS header, version '1.6'/' 3'/' 5':
|
||||
# Offset Field Data type Length Details
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# 0 Filetype string 38 Specifies the file type and version.
|
||||
# "EasyWorship Schedule File Version 1.6" or
|
||||
# "EasyWorship Schedule File Version 3" or
|
||||
# "EasyWorship Schedule File Version 5"
|
||||
# 40/48/56 Entry count int32le 4 Number of items in the schedule
|
||||
# 44/52/60 Entry length int16le 2 Length of schedule entries: 0x0718 = 1816
|
||||
# Get file version
|
||||
type, = struct.unpack('<38s', self.ews_file.read(38))
|
||||
version = type.decode()[-3:]
|
||||
# Set fileposition based on filetype/version
|
||||
file_pos = 0
|
||||
if version == ' 5':
|
||||
file_pos = 56
|
||||
elif version == ' 3':
|
||||
file_pos = 48
|
||||
elif version == '1.6':
|
||||
file_pos = 40
|
||||
else:
|
||||
log.debug('Given ews file is of unknown version.')
|
||||
return
|
||||
entry_count = self.get_i32(file_pos)
|
||||
entry_length = self.get_i16(file_pos+4)
|
||||
file_pos += 6
|
||||
self.import_wizard.progress_bar.setMaximum(entry_count)
|
||||
# Loop over songs
|
||||
for i in range(entry_count):
|
||||
# Load EWS entry metadata:
|
||||
# Offset Field Data type Length Details
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
# 0 Title cstring 50
|
||||
# 307 Author cstring 50
|
||||
# 358 Copyright cstring 100
|
||||
# 459 Administrator cstring 50
|
||||
# 800 Content pointer int32le 4 Position of the content for this entry.
|
||||
# 820 Content type int32le 4 0x01 = Song, 0x02 = Scripture, 0x03 = Presentation,
|
||||
# 0x04 = Video, 0x05 = Live video, 0x07 = Image,
|
||||
# 0x08 = Audio, 0x09 = Web
|
||||
# 1410 Song number cstring 10
|
||||
self.set_defaults()
|
||||
self.title = self.get_string(file_pos + 0, 50)
|
||||
authors = self.get_string(file_pos + 307, 50)
|
||||
copyright = self.get_string(file_pos + 358, 100)
|
||||
admin = self.get_string(file_pos + 459, 50)
|
||||
cont_ptr = self.get_i32(file_pos + 800)
|
||||
cont_type = self.get_i32(file_pos + 820)
|
||||
self.ccli_number = self.get_string(file_pos + 1410, 10)
|
||||
# Only handle content type 1 (songs)
|
||||
if cont_type != 1:
|
||||
file_pos += entry_length
|
||||
continue
|
||||
# Load song content
|
||||
# Offset Field Data type Length Details
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
# 0 Length int32le 4 Length (L) of content, including the compressed content
|
||||
# and the following fields (14 bytes total).
|
||||
# 4 Content string L-14 Content compressed with deflate.
|
||||
# Checksum int32be 4 Alder-32 checksum.
|
||||
# (unknown) 4 0x51 0x4b 0x03 0x04
|
||||
# Content length int32le 4 Length of content after decompression
|
||||
content_length = self.get_i32(cont_ptr)
|
||||
deflated_content = self.get_bytes(cont_ptr + 4, content_length - 10)
|
||||
deflated_length = self.get_i32(cont_ptr + 4 + content_length - 6)
|
||||
inflated_content = zlib.decompress(deflated_content, 15, deflated_length)
|
||||
if copyright:
|
||||
self.copyright = copyright
|
||||
if admin:
|
||||
if copyright:
|
||||
self.copyright += ', '
|
||||
self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
|
||||
'Administered by %s') % admin
|
||||
# Set the SongImport object members.
|
||||
self.set_song_import_object(authors, inflated_content)
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
if not self.finish():
|
||||
self.log_error(self.import_source)
|
||||
# Set file_pos for next entry
|
||||
file_pos += entry_length
|
||||
self.ews_file.close()
|
||||
|
||||
def import_db(self):
|
||||
"""
|
||||
Import the songs from the database
|
||||
"""
|
||||
# Open the DB and MB files if they exist
|
||||
import_source_mb = self.import_source.replace('.DB', '.MB')
|
||||
@ -176,7 +288,6 @@ class EasyWorshipSongImport(SongImport):
|
||||
ccli = self.get_field(fi_ccli)
|
||||
authors = self.get_field(fi_author)
|
||||
words = self.get_field(fi_words)
|
||||
# Set the SongImport object members.
|
||||
if copy:
|
||||
self.copyright = copy.decode()
|
||||
if admin:
|
||||
@ -186,15 +297,35 @@ class EasyWorshipSongImport(SongImport):
|
||||
'Administered by %s') % admin.decode()
|
||||
if ccli:
|
||||
self.ccli_number = ccli.decode()
|
||||
if authors:
|
||||
authors = authors.decode()
|
||||
else:
|
||||
authors = ''
|
||||
# Set the SongImport object members.
|
||||
self.set_song_import_object(authors, words)
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
if not self.finish():
|
||||
self.log_error(self.import_source)
|
||||
db_file.close()
|
||||
self.memo_file.close()
|
||||
|
||||
def set_song_import_object(self, authors, words):
|
||||
"""
|
||||
Set the SongImport object members.
|
||||
|
||||
:param authors: String with authons
|
||||
:param words: Bytes with rtf-encoding
|
||||
"""
|
||||
if authors:
|
||||
# Split up the authors
|
||||
author_list = authors.split(b'/')
|
||||
author_list = authors.split('/')
|
||||
if len(author_list) < 2:
|
||||
author_list = authors.split(b';')
|
||||
author_list = authors.split(';')
|
||||
if len(author_list) < 2:
|
||||
author_list = authors.split(b',')
|
||||
author_list = authors.split(',')
|
||||
for author_name in author_list:
|
||||
self.add_author(author_name.decode().strip())
|
||||
self.add_author(author_name.strip())
|
||||
if words:
|
||||
# Format the lyrics
|
||||
result = strip_rtf(words.decode(), self.encoding)
|
||||
@ -236,19 +367,12 @@ class EasyWorshipSongImport(SongImport):
|
||||
if len(self.comments) > 5:
|
||||
self.comments += str(translate('SongsPlugin.EasyWorshipSongImport',
|
||||
'\n[above are Song Tags with notes imported from EasyWorship]'))
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
if not self.finish():
|
||||
self.log_error(self.import_source)
|
||||
db_file.close()
|
||||
self.memo_file.close()
|
||||
|
||||
def find_field(self, field_name):
|
||||
"""
|
||||
Find a field in the descriptions
|
||||
|
||||
:param field_name: field to find
|
||||
:return:
|
||||
"""
|
||||
return [i for i, x in enumerate(self.field_descriptions) if x.name == field_name][0]
|
||||
|
||||
@ -285,7 +409,7 @@ class EasyWorshipSongImport(SongImport):
|
||||
Extract the field
|
||||
|
||||
:param field_desc_index: Field index value
|
||||
:return:
|
||||
:return: The field value
|
||||
"""
|
||||
field = self.fields[field_desc_index]
|
||||
field_desc = self.field_descriptions[field_desc_index]
|
||||
@ -323,3 +447,52 @@ class EasyWorshipSongImport(SongImport):
|
||||
return self.memo_file.read(blob_size)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_bytes(self, pos, length):
|
||||
"""
|
||||
Get bytes from ews_file
|
||||
|
||||
:param pos: Position to read from
|
||||
:param length: Bytes to read
|
||||
:return: Bytes read
|
||||
"""
|
||||
self.ews_file.seek(pos)
|
||||
return self.ews_file.read(length)
|
||||
|
||||
def get_string(self, pos, length):
|
||||
"""
|
||||
Get string from ews_file
|
||||
|
||||
:param pos: Position to read from
|
||||
:param length: Characters to read
|
||||
:return: String read
|
||||
"""
|
||||
bytes = self.get_bytes(pos, length)
|
||||
mask = '<' + str(length) + 's'
|
||||
byte_str, = struct.unpack(mask, bytes)
|
||||
return byte_str.decode('unicode-escape').replace('\0', '').strip()
|
||||
|
||||
def get_i16(self, pos):
|
||||
"""
|
||||
Get short int from ews_file
|
||||
|
||||
:param pos: Position to read from
|
||||
:return: Short integer read
|
||||
"""
|
||||
|
||||
bytes = self.get_bytes(pos, 2)
|
||||
mask = '<h'
|
||||
number, = struct.unpack(mask, bytes)
|
||||
return number
|
||||
|
||||
def get_i32(self, pos):
|
||||
"""
|
||||
Get long int from ews_file
|
||||
|
||||
:param pos: Position to read from
|
||||
:return: Long integer read
|
||||
"""
|
||||
bytes = self.get_bytes(pos, 4)
|
||||
mask = '<i'
|
||||
number, = struct.unpack(mask, bytes)
|
||||
return number
|
||||
|
@ -153,19 +153,20 @@ class SongFormat(object):
|
||||
CCLI = 3
|
||||
DreamBeam = 4
|
||||
EasySlides = 5
|
||||
EasyWorship = 6
|
||||
FoilPresenter = 7
|
||||
MediaShout = 8
|
||||
OpenSong = 9
|
||||
PowerSong = 10
|
||||
SongBeamer = 11
|
||||
SongPro = 12
|
||||
SongShowPlus = 13
|
||||
SongsOfFellowship = 14
|
||||
SundayPlus = 15
|
||||
WordsOfWorship = 16
|
||||
WorshipCenterPro = 17
|
||||
ZionWorx = 18
|
||||
EasyWorshipDB = 6
|
||||
EasyWorshipService = 7
|
||||
FoilPresenter = 8
|
||||
MediaShout = 9
|
||||
OpenSong = 10
|
||||
PowerSong = 11
|
||||
SongBeamer = 12
|
||||
SongPro = 13
|
||||
SongShowPlus = 14
|
||||
SongsOfFellowship = 15
|
||||
SundayPlus = 16
|
||||
WordsOfWorship = 17
|
||||
WorshipCenterPro = 18
|
||||
ZionWorx = 19
|
||||
|
||||
# Set optional attribute defaults
|
||||
__defaults__ = {
|
||||
@ -224,13 +225,20 @@ class SongFormat(object):
|
||||
'selectMode': SongFormatSelect.SingleFile,
|
||||
'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'EasySlides XML File')
|
||||
},
|
||||
EasyWorship: {
|
||||
EasyWorshipDB: {
|
||||
'class': EasyWorshipSongImport,
|
||||
'name': 'EasyWorship',
|
||||
'name': 'EasyWorship Song Database',
|
||||
'prefix': 'ew',
|
||||
'selectMode': SongFormatSelect.SingleFile,
|
||||
'filter': '%s (*.db)' % translate('SongsPlugin.ImportWizardForm', 'EasyWorship Song Database')
|
||||
},
|
||||
EasyWorshipService: {
|
||||
'class': EasyWorshipSongImport,
|
||||
'name': 'EasyWorship Service File',
|
||||
'prefix': 'ew',
|
||||
'selectMode': SongFormatSelect.SingleFile,
|
||||
'filter': '%s (*.ews)' % translate('SongsPlugin.ImportWizardForm', 'EasyWorship Service File')
|
||||
},
|
||||
FoilPresenter: {
|
||||
'class': FoilPresenterImport,
|
||||
'name': 'Foilpresenter',
|
||||
@ -341,7 +349,8 @@ class SongFormat(object):
|
||||
SongFormat.CCLI,
|
||||
SongFormat.DreamBeam,
|
||||
SongFormat.EasySlides,
|
||||
SongFormat.EasyWorship,
|
||||
SongFormat.EasyWorshipDB,
|
||||
SongFormat.EasyWorshipService,
|
||||
SongFormat.FoilPresenter,
|
||||
SongFormat.MediaShout,
|
||||
SongFormat.OpenSong,
|
||||
|
@ -518,14 +518,6 @@ class SongMediaItem(MediaManagerItem):
|
||||
log.debug('service_load')
|
||||
if self.plugin.status != PluginStatus.Active or not item.data_string:
|
||||
return
|
||||
if item.data_string['title'].find('@') == -1:
|
||||
# FIXME: This file seems to be an old one (prior to 1.9.5), which means, that the search title
|
||||
# (data_string[u'title']) is probably wrong. We add "@" to search title and hope that we do not add any
|
||||
# duplicate. This should work for songs without alternate title.
|
||||
temp = (re.compile(r'\W+', re.UNICODE).sub(' ', item.data_string['title'].strip()) + '@').strip().lower()
|
||||
search_results = \
|
||||
self.plugin.manager.get_all_objects(Song, Song.search_title == temp, Song.search_title.asc())
|
||||
else:
|
||||
search_results = self.plugin.manager.get_all_objects(
|
||||
Song, Song.search_title == item.data_string['title'], Song.search_title.asc())
|
||||
edit_id = 0
|
||||
|
@ -171,7 +171,7 @@ class SongBeamerImport(SongImport):
|
||||
|
||||
:param line: The line in the file. It should consist of a tag and a value for this tag (unicode)::
|
||||
|
||||
u'#Title=Nearer my God to Thee'
|
||||
'#Title=Nearer my God to Thee'
|
||||
"""
|
||||
tag_val = line.split('=', 1)
|
||||
if len(tag_val) == 1:
|
||||
|
@ -146,14 +146,14 @@ class SongSelectImport(object):
|
||||
try:
|
||||
song_page = BeautifulSoup(self.opener.open(song['link']).read(), 'lxml')
|
||||
except (TypeError, HTTPError) as e:
|
||||
log.exception(u'Could not get song from SongSelect, %s', e)
|
||||
log.exception('Could not get song from SongSelect, %s', e)
|
||||
return None
|
||||
if callback:
|
||||
callback()
|
||||
try:
|
||||
lyrics_page = BeautifulSoup(self.opener.open(song['link'] + '/lyrics').read(), 'lxml')
|
||||
except (TypeError, HTTPError):
|
||||
log.exception(u'Could not get lyrics from SongSelect')
|
||||
log.exception('Could not get lyrics from SongSelect')
|
||||
return None
|
||||
if callback:
|
||||
callback()
|
||||
|
@ -344,7 +344,7 @@ class OpenLyrics(object):
|
||||
"""
|
||||
Tests the given text for not closed formatting tags and returns a tuple consisting of two unicode strings::
|
||||
|
||||
(u'{st}{r}', u'{/r}{/st}')
|
||||
('{st}{r}', '{/r}{/st}')
|
||||
|
||||
The first unicode string are the start tags (for the next slide). The second unicode string are the end tags.
|
||||
|
||||
|
@ -305,7 +305,7 @@ class TestLib(TestCase):
|
||||
# WHEN: We convert an image to a byte array
|
||||
result = image_to_byte(mocked_image)
|
||||
|
||||
# THEN: We should receive a value of u'base64mock'
|
||||
# THEN: We should receive a value of 'base64mock'
|
||||
MockedQtCore.QByteArray.assert_called_with()
|
||||
MockedQtCore.QBuffer.assert_called_with(mocked_byte_array)
|
||||
mocked_buffer.open.assert_called_with('writeonly')
|
||||
|
@ -35,9 +35,107 @@ from PyQt4 import QtGui, QtCore
|
||||
|
||||
from openlp.core.common import Settings
|
||||
from openlp.core.utils import ActionList
|
||||
from openlp.core.utils.actions import CategoryActionList
|
||||
from tests.functional import MagicMock
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
class TestCategoryActionList(TestCase):
|
||||
def setUp(self):
|
||||
"""
|
||||
Create an instance and a few example actions.
|
||||
"""
|
||||
self.action1 = MagicMock()
|
||||
self.action1.text.return_value = 'first'
|
||||
self.action2 = MagicMock()
|
||||
self.action2.text.return_value = 'second'
|
||||
self.list = CategoryActionList()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Clean up
|
||||
"""
|
||||
del self.list
|
||||
|
||||
def contains_test(self):
|
||||
"""
|
||||
Test the __contains__() method
|
||||
"""
|
||||
# GIVEN: The list.
|
||||
# WHEN: Add an action
|
||||
self.list.append(self.action1)
|
||||
|
||||
# THEN: The actions should (not) be in the list.
|
||||
self.assertTrue(self.action1 in self.list)
|
||||
self.assertFalse(self.action2 in self.list)
|
||||
|
||||
def len_test(self):
|
||||
"""
|
||||
Test the __len__ method
|
||||
"""
|
||||
# GIVEN: The list.
|
||||
# WHEN: Do nothing.
|
||||
# THEN: Check the length.
|
||||
self.assertEqual(len(self.list), 0, "The length should be 0.")
|
||||
|
||||
# GIVEN: The list.
|
||||
# WHEN: Append an action.
|
||||
self.list.append(self.action1)
|
||||
|
||||
# THEN: Check the length.
|
||||
self.assertEqual(len(self.list), 1, "The length should be 1.")
|
||||
|
||||
def append_test(self):
|
||||
"""
|
||||
Test the append() method
|
||||
"""
|
||||
# GIVEN: The list.
|
||||
# WHEN: Append an action.
|
||||
self.list.append(self.action1)
|
||||
self.list.append(self.action2)
|
||||
|
||||
# THEN: Check if the actions are in the list and check if they have the correct weights.
|
||||
self.assertTrue(self.action1 in self.list)
|
||||
self.assertTrue(self.action2 in self.list)
|
||||
self.assertEqual(self.list.actions[0], (0, self.action1))
|
||||
self.assertEqual(self.list.actions[1], (1, self.action2))
|
||||
|
||||
def add_test(self):
|
||||
"""
|
||||
Test the add() method
|
||||
"""
|
||||
# GIVEN: The list and weights.
|
||||
action1_weight = 42
|
||||
action2_weight = 41
|
||||
|
||||
# WHEN: Add actions and their weights.
|
||||
self.list.add(self.action1, action1_weight)
|
||||
self.list.add(self.action2, action2_weight)
|
||||
|
||||
# THEN: Check if they were added and have the specified weights.
|
||||
self.assertTrue(self.action1 in self.list)
|
||||
self.assertTrue(self.action2 in self.list)
|
||||
# Now check if action1 is second and action2 is first (due to their weights).
|
||||
self.assertEqual(self.list.actions[0], (41, self.action2))
|
||||
self.assertEqual(self.list.actions[1], (42, self.action1))
|
||||
|
||||
def remove_test(self):
|
||||
"""
|
||||
Test the remove() method
|
||||
"""
|
||||
# GIVEN: The list
|
||||
self.list.append(self.action1)
|
||||
|
||||
# WHEN: Delete an item from the list.
|
||||
self.list.remove(self.action1)
|
||||
|
||||
# THEN: Now the element should not be in the list anymore.
|
||||
self.assertFalse(self.action1 in self.list)
|
||||
|
||||
# THEN: Check if an exception is raised when trying to remove a not present action.
|
||||
self.assertRaises(ValueError, self.list.remove, self.action2)
|
||||
|
||||
|
||||
class TestActionList(TestCase, TestMixin):
|
||||
"""
|
||||
Test the ActionList class
|
||||
|
@ -250,7 +250,7 @@ class TestUtils(TestCase):
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
result = 'Linux' in user_agent or 'CrOS' in user_agent
|
||||
self.assertTrue(result, u'The user agent should be a valid Linux user agent')
|
||||
self.assertTrue(result, 'The user agent should be a valid Linux user agent')
|
||||
|
||||
def get_user_agent_windows_test(self):
|
||||
"""
|
||||
@ -265,7 +265,7 @@ class TestUtils(TestCase):
|
||||
user_agent = _get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
self.assertIn('Windows', user_agent, u'The user agent should be a valid Windows user agent')
|
||||
self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent')
|
||||
|
||||
def get_user_agent_macos_test(self):
|
||||
"""
|
||||
@ -280,7 +280,7 @@ class TestUtils(TestCase):
|
||||
user_agent = _get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
self.assertIn('Mac OS X', user_agent, u'The user agent should be a valid OS X user agent')
|
||||
self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent')
|
||||
|
||||
def get_user_agent_default_test(self):
|
||||
"""
|
||||
@ -295,7 +295,7 @@ class TestUtils(TestCase):
|
||||
user_agent = _get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
self.assertIn('NetBSD', user_agent, u'The user agent should be the default user agent')
|
||||
self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent')
|
||||
|
||||
def get_web_page_no_url_test(self):
|
||||
"""
|
||||
|
@ -69,6 +69,20 @@ SONG_TEST_DATA = [
|
||||
'Just to bow and receive a new blessing,\nIn the beautiful garden of prayer.', 'v3')],
|
||||
'verse_order_list': []}]
|
||||
|
||||
EWS_SONG_TEST_DATA =\
|
||||
{'title': 'Vi pløjed og vi så\'de',
|
||||
'authors': ['Matthias Claudius'],
|
||||
'verses':
|
||||
[('Vi pløjed og vi så\'de\nvor sæd i sorten jord,\nså bad vi ham os hjælpe,\nsom højt i Himlen bor,\n'
|
||||
'og han lod snefald hegne\nmod frosten barsk og hård,\nhan lod det tø og regne\nog varme mildt i vår.',
|
||||
'v1'),
|
||||
('Alle gode gaver\nde kommer ovenned,\nså tak da Gud, ja, pris dog Gud\nfor al hans kærlighed!', 'c1'),
|
||||
('Han er jo den, hvis vilje\nopholder alle ting,\nhan klæder markens lilje\nog runder himlens ring,\n'
|
||||
'ham lyder vind og vove,\nham rører ravnes nød,\nhvi skulle ej hans småbørn\nda og få dagligt brød?', 'v2'),
|
||||
('Ja, tak, du kære Fader,\nså mild, så rig, så rund,\nfor korn i hæs og lader,\nfor godt i allen stund!\n'
|
||||
'Vi kan jo intet give,\nsom nogen ting er værd,\nmen tag vort stakkels hjerte,\nså ringe som det er!',
|
||||
'v3')]}
|
||||
|
||||
|
||||
class EasyWorshipSongImportLogger(EasyWorshipSongImport):
|
||||
"""
|
||||
@ -357,9 +371,9 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800')
|
||||
mocked_retrieve_windows_encoding.assert_call(encoding)
|
||||
|
||||
def file_import_test(self):
|
||||
def db_file_import_test(self):
|
||||
"""
|
||||
Test the actual import of real song files and check that the imported data is correct.
|
||||
Test the actual import of real song database files and check that the imported data is correct.
|
||||
"""
|
||||
|
||||
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard",
|
||||
@ -386,10 +400,11 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
|
||||
# WHEN: Importing each file
|
||||
importer.import_source = os.path.join(TEST_PATH, 'Songs.DB')
|
||||
import_result = importer.do_import()
|
||||
|
||||
# THEN: do_import should return none, the song data should be as expected, and finish should have been
|
||||
# called.
|
||||
self.assertIsNone(importer.do_import(), 'do_import should return None when it has completed')
|
||||
self.assertIsNone(import_result, 'do_import should return None when it has completed')
|
||||
for song_data in SONG_TEST_DATA:
|
||||
title = song_data['title']
|
||||
author_calls = song_data['authors']
|
||||
@ -411,3 +426,44 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
self.assertEqual(importer.verse_order_list, verse_order_list,
|
||||
'verse_order_list for %s should be %s' % (title, verse_order_list))
|
||||
mocked_finish.assert_called_with()
|
||||
|
||||
def ews_file_import_test(self):
|
||||
"""
|
||||
Test the actual import of song from ews file and check that the imported data is correct.
|
||||
"""
|
||||
|
||||
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard",
|
||||
# and mocked out "author", "add_copyright", "add_verse", "finish" methods.
|
||||
with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \
|
||||
patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') \
|
||||
as mocked_retrieve_windows_encoding:
|
||||
mocked_retrieve_windows_encoding.return_value = 'cp1252'
|
||||
mocked_manager = MagicMock()
|
||||
mocked_import_wizard = MagicMock()
|
||||
mocked_add_author = MagicMock()
|
||||
mocked_add_verse = MagicMock()
|
||||
mocked_finish = MagicMock()
|
||||
mocked_title = MagicMock()
|
||||
mocked_finish.return_value = True
|
||||
importer = EasyWorshipSongImportLogger(mocked_manager)
|
||||
importer.import_wizard = mocked_import_wizard
|
||||
importer.stop_import_flag = False
|
||||
importer.add_author = mocked_add_author
|
||||
importer.add_verse = mocked_add_verse
|
||||
importer.title = mocked_title
|
||||
importer.finish = mocked_finish
|
||||
importer.topics = []
|
||||
|
||||
# WHEN: Importing ews file
|
||||
importer.import_source = os.path.join(TEST_PATH, 'test1.ews')
|
||||
import_result = importer.do_import()
|
||||
|
||||
# THEN: do_import should return none, the song data should be as expected, and finish should have been
|
||||
# called.
|
||||
title = EWS_SONG_TEST_DATA['title']
|
||||
self.assertIsNone(import_result, 'do_import should return None when it has completed')
|
||||
self.assertIn(title, importer._title_assignment_list, 'title for should be "%s"' % title)
|
||||
mocked_add_author.assert_any_call(EWS_SONG_TEST_DATA['authors'][0])
|
||||
for verse_text, verse_tag in EWS_SONG_TEST_DATA['verses']:
|
||||
mocked_add_verse.assert_any_call(verse_text, verse_tag)
|
||||
mocked_finish.assert_called_with()
|
||||
|
28
tests/interfaces/openlp_core_common/__init__.py
Normal file
28
tests/interfaces/openlp_core_common/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- 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 #
|
||||
###############################################################################
|
@ -27,34 +27,39 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
Test the openlp.core.ui.splashscreen class.
|
||||
Module to test the :mod:`~openlp.core.common.historycombobox` module.
|
||||
"""
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4 import QtCore, QtGui, QtTest
|
||||
|
||||
from openlp.core.ui import SplashScreen
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.common import HistoryComboBox
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
from tests.interfaces import MagicMock, patch
|
||||
|
||||
|
||||
class TestSplashScreen(TestCase, TestMixin):
|
||||
class TestHistoryComboBox(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.combo = HistoryComboBox(self.main_window)
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Delete all the C++ objects at the end so that we don't have a segfault
|
||||
"""
|
||||
del self.app
|
||||
del self.main_window
|
||||
del self.combo
|
||||
|
||||
def setupUi_test(self):
|
||||
def getItems_test(self):
|
||||
"""
|
||||
Test if the setupUi method....
|
||||
Test the getItems() method
|
||||
"""
|
||||
# GIVEN: A splash screen instance.
|
||||
splash = SplashScreen()
|
||||
# GIVEN: The combo.
|
||||
|
||||
# THEN: Check if the splash has a setupUi method.
|
||||
assert hasattr(splash, 'setupUi'), 'The Splash Screen should have a setupUi() method.'
|
||||
# WHEN: Add two items.
|
||||
self.combo.addItem('test1')
|
||||
self.combo.addItem('test2')
|
||||
|
||||
# THEN: The list of items should contain both strings.
|
||||
self.assertEqual(self.combo.getItems(), ['test1', 'test2'])
|
@ -30,7 +30,6 @@
|
||||
Module to test the EditCustomForm.
|
||||
"""
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from PyQt4 import QtCore, QtGui, QtTest
|
||||
|
||||
@ -127,9 +126,3 @@ class TestSearchEdit(TestCase, TestMixin):
|
||||
# THEN: The search edit text should be cleared and the button be hidden.
|
||||
assert not self.search_edit.text(), "The search edit should not have any text."
|
||||
assert self.search_edit.clear_button.isHidden(), "The clear button should be hidden."
|
||||
|
||||
def resize_event_test(self):
|
||||
"""
|
||||
Just check if the resizeEvent() method is re-implemented.
|
||||
"""
|
||||
assert hasattr(self.search_edit, "resizeEvent"), "The search edit should re-implement the resizeEvent method."
|
||||
|
@ -89,7 +89,7 @@ class TestStartFileRenameForm(TestCase, TestMixin):
|
||||
Test that the file_name_edit setFocus has called with True when executed
|
||||
"""
|
||||
# GIVEN: A mocked QDialog.exec_() method and mocked file_name_edit.setFocus() method.
|
||||
with patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec:
|
||||
with patch('PyQt4.QtGui.QDialog.exec_'):
|
||||
mocked_set_focus = MagicMock()
|
||||
self.form.file_name_edit.setFocus = mocked_set_focus
|
||||
|
||||
|
78
tests/interfaces/openlp_core_ui/test_shortcutlistform.py
Normal file
78
tests/interfaces/openlp_core_ui/test_shortcutlistform.py
Normal file
@ -0,0 +1,78 @@
|
||||
# -*- 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
Package to test the openlp.core.ui.shortcutform package.
|
||||
"""
|
||||
from unittest import TestCase
|
||||
|
||||
from PyQt4 import QtCore, QtGui, QtTest
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.ui.shortcutlistform import ShortcutListForm
|
||||
from tests.interfaces import patch
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
class TestShortcutform(TestCase, TestMixin):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = ShortcutListForm()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Delete all the C++ objects at the end so that we don't have a segfault
|
||||
"""
|
||||
del self.form
|
||||
del self.main_window
|
||||
|
||||
def adjust_button_test(self):
|
||||
"""
|
||||
Test the _adjust_button() method
|
||||
"""
|
||||
# GIVEN: A button.
|
||||
button = QtGui.QPushButton()
|
||||
checked = True
|
||||
enabled = True
|
||||
text = "new!"
|
||||
|
||||
# WHEN: Call the method.
|
||||
with patch('PyQt4.QtGui.QPushButton.setChecked') as mocked_check_method:
|
||||
self.form._adjust_button(button, checked, enabled, text)
|
||||
|
||||
# THEN: The button should be changed.
|
||||
self.assertEqual(button.text(), text, "The text should match.")
|
||||
mocked_check_method.assert_called_once_with(True)
|
||||
self.assertEqual(button.isEnabled(), enabled, "The button should be disabled.")
|
BIN
tests/resources/easyworshipsongs/test1.ews
Normal file
BIN
tests/resources/easyworshipsongs/test1.ews
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user