forked from openlp/openlp
head
This commit is contained in:
commit
4560d39ad9
@ -2,6 +2,7 @@
|
||||
*.*~
|
||||
\#*\#
|
||||
*.eric4project
|
||||
*.eric5project
|
||||
*.ropeproject
|
||||
*.e4*
|
||||
.eric4project
|
||||
|
@ -30,7 +30,6 @@
|
||||
The :mod:`openlp` module contains all the project produced OpenLP functionality
|
||||
"""
|
||||
|
||||
import openlp.core
|
||||
import openlp.plugins
|
||||
from openlp import core, plugins
|
||||
|
||||
__all__ = ['core', 'plugins']
|
||||
|
@ -38,7 +38,7 @@ import traceback
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
log = logging.getLogger(__name__+'.__init__')
|
||||
log = logging.getLogger(__name__ + '.__init__')
|
||||
|
||||
|
||||
FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)')
|
||||
@ -76,6 +76,9 @@ def check_directory_exists(directory, do_not_log=False):
|
||||
def get_frozen_path(frozen_option, non_frozen_option):
|
||||
"""
|
||||
Return a path based on the system status.
|
||||
|
||||
:param frozen_option:
|
||||
:param non_frozen_option:
|
||||
"""
|
||||
if hasattr(sys, 'frozen') and sys.frozen == 1:
|
||||
return frozen_option
|
||||
|
@ -39,7 +39,7 @@ from PyQt4 import QtCore, QtGui, Qt
|
||||
|
||||
from openlp.core.common import translate
|
||||
|
||||
log = logging.getLogger(__name__+'.__init__')
|
||||
log = logging.getLogger(__name__ + '.__init__')
|
||||
|
||||
|
||||
class ServiceItemContext(object):
|
||||
|
@ -168,29 +168,29 @@ class MediaManagerItem(QtGui.QWidget, RegistryProperties):
|
||||
Create buttons for the media item toolbar
|
||||
"""
|
||||
toolbar_actions = []
|
||||
## Import Button ##
|
||||
# Import Button
|
||||
if self.has_import_icon:
|
||||
toolbar_actions.append(['Import', StringContent.Import,
|
||||
':/general/general_import.png', self.on_import_click])
|
||||
## Load Button ##
|
||||
# Load Button
|
||||
if self.has_file_icon:
|
||||
toolbar_actions.append(['Load', StringContent.Load, ':/general/general_open.png', self.on_file_click])
|
||||
## New Button ##
|
||||
# New Button
|
||||
if self.has_new_icon:
|
||||
toolbar_actions.append(['New', StringContent.New, ':/general/general_new.png', self.on_new_click])
|
||||
## Edit Button ##
|
||||
# Edit Button
|
||||
if self.has_edit_icon:
|
||||
toolbar_actions.append(['Edit', StringContent.Edit, ':/general/general_edit.png', self.on_edit_click])
|
||||
## Delete Button ##
|
||||
# Delete Button
|
||||
if self.has_delete_icon:
|
||||
toolbar_actions.append(['Delete', StringContent.Delete,
|
||||
':/general/general_delete.png', self.on_delete_click])
|
||||
## Preview ##
|
||||
# Preview
|
||||
toolbar_actions.append(['Preview', StringContent.Preview,
|
||||
':/general/general_preview.png', self.on_preview_click])
|
||||
## Live Button ##
|
||||
# Live Button
|
||||
toolbar_actions.append(['Live', StringContent.Live, ':/general/general_live.png', self.on_live_click])
|
||||
## Add to service Button ##
|
||||
# Add to service Button
|
||||
toolbar_actions.append(['Service', StringContent.Service, ':/general/general_add.png', self.on_add_click])
|
||||
for action in toolbar_actions:
|
||||
if action[0] == StringContent.Preview:
|
||||
|
@ -101,7 +101,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
|
||||
``add_import_menu_item(import_menu)``
|
||||
Add an item to the Import menu.
|
||||
|
||||
``add_export_menu_Item(export_menu)``
|
||||
``add_export_menu_item(export_menu)``
|
||||
Add an item to the Export menu.
|
||||
|
||||
``create_settings_tab()``
|
||||
@ -226,7 +226,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_export_menu_Item(self, export_menu):
|
||||
def add_export_menu_item(self, export_menu):
|
||||
"""
|
||||
Create a menu item and add it to the "Export" menu.
|
||||
|
||||
@ -329,22 +329,24 @@ class Plugin(QtCore.QObject, RegistryProperties):
|
||||
def set_plugin_ui_text_strings(self, tooltips):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
|
||||
:param tooltips:
|
||||
"""
|
||||
## Load Action ##
|
||||
# Load Action
|
||||
self.__set_name_text_string(StringContent.Load, UiStrings().Load, tooltips['load'])
|
||||
## Import Action ##
|
||||
# Import Action
|
||||
self.__set_name_text_string(StringContent.Import, UiStrings().Import, tooltips['import'])
|
||||
## New Action ##
|
||||
# New Action
|
||||
self.__set_name_text_string(StringContent.New, UiStrings().Add, tooltips['new'])
|
||||
## Edit Action ##
|
||||
# Edit Action
|
||||
self.__set_name_text_string(StringContent.Edit, UiStrings().Edit, tooltips['edit'])
|
||||
## Delete Action ##
|
||||
# Delete Action
|
||||
self.__set_name_text_string(StringContent.Delete, UiStrings().Delete, tooltips['delete'])
|
||||
## Preview Action ##
|
||||
# Preview Action
|
||||
self.__set_name_text_string(StringContent.Preview, UiStrings().Preview, tooltips['preview'])
|
||||
## Send Live Action ##
|
||||
# Send Live Action
|
||||
self.__set_name_text_string(StringContent.Live, UiStrings().Live, tooltips['live'])
|
||||
## Add to Service Action ##
|
||||
# Add to Service Action
|
||||
self.__set_name_text_string(StringContent.Service, UiStrings().Service, tooltips['service'])
|
||||
|
||||
def __set_name_text_string(self, name, title, tooltip):
|
||||
|
@ -161,7 +161,7 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
if plugin.status is not PluginStatus.Disabled:
|
||||
plugin.add_export_menu_Item(self.main_window.file_export_menu)
|
||||
plugin.add_export_menu_item(self.main_window.file_export_menu)
|
||||
|
||||
def hook_tools_menu(self):
|
||||
"""
|
||||
|
@ -108,6 +108,9 @@ class ItemCapabilities(object):
|
||||
``CanAutoStartForLive``
|
||||
The capability to ignore the do not play if display blank flag.
|
||||
|
||||
``CanEditTitle``
|
||||
The capability to edit the title of the item
|
||||
|
||||
"""
|
||||
CanPreview = 1
|
||||
CanEdit = 2
|
||||
@ -125,6 +128,7 @@ class ItemCapabilities(object):
|
||||
CanWordSplit = 14
|
||||
HasBackgroundAudio = 15
|
||||
CanAutoStartForLive = 16
|
||||
CanEditTitle = 17
|
||||
|
||||
|
||||
class ServiceItem(RegistryProperties):
|
||||
@ -383,7 +387,7 @@ class ServiceItem(RegistryProperties):
|
||||
self.will_auto_start = header.get('will_auto_start', False)
|
||||
self.processor = header.get('processor', None)
|
||||
self.has_original_files = True
|
||||
#TODO Remove me in 2,3 build phase
|
||||
# TODO: Remove me in 2,3 build phase
|
||||
if self.is_capable(ItemCapabilities.HasDetailedTitleDisplay):
|
||||
self.capabilities.remove(ItemCapabilities.HasDetailedTitleDisplay)
|
||||
self.processor = self.title
|
||||
@ -423,7 +427,7 @@ class ServiceItem(RegistryProperties):
|
||||
"""
|
||||
Returns the title of the service item.
|
||||
"""
|
||||
if self.is_text():
|
||||
if self.is_text() or ItemCapabilities.CanEditTitle in self.capabilities:
|
||||
return self.title
|
||||
else:
|
||||
if len(self._raw_frames) > 1:
|
||||
|
@ -173,7 +173,7 @@ def create_button(parent, name, **kwargs):
|
||||
kwargs.setdefault('tooltip', translate('OpenLP.Ui', 'Move selection down one position.'))
|
||||
else:
|
||||
log.warn('The role "%s" is not defined in create_push_button().', role)
|
||||
if kwargs.pop('class', '') == 'toolbutton':
|
||||
if kwargs.pop('btn_class', '') == 'toolbutton':
|
||||
button = QtGui.QToolButton(parent)
|
||||
else:
|
||||
button = QtGui.QPushButton(parent)
|
||||
|
@ -95,15 +95,15 @@ class Ui_ExceptionDialog(object):
|
||||
Translate the widgets on the fly.
|
||||
"""
|
||||
exception_dialog.setWindowTitle(translate('OpenLP.ExceptionDialog', 'Error Occurred'))
|
||||
self.description_explanation.setText(translate('OpenLP.ExceptionDialog',
|
||||
'Please enter a description of what you were doing to cause this error '
|
||||
'\n(Minimum 20 characters)'))
|
||||
self.message_label.setText(translate('OpenLP.ExceptionDialog', 'Oops! '
|
||||
'OpenLP hit a problem, and couldn\'t recover. The text in the box '
|
||||
'below contains information that might be helpful to the OpenLP '
|
||||
'developers, so please e-mail it to bugs@openlp.org, along with a '
|
||||
'detailed description of what you were doing when the problem '
|
||||
'occurred.'))
|
||||
self.description_explanation.setText(
|
||||
translate('OpenLP.ExceptionDialog', 'Please enter a description of what you were doing to cause this error '
|
||||
'\n(Minimum 20 characters)'))
|
||||
self.message_label.setText(
|
||||
translate('OpenLP.ExceptionDialog', 'Oops! OpenLP hit a problem, and couldn\'t recover. The text in the '
|
||||
'box below contains information that might be helpful to the OpenLP '
|
||||
'developers, so please e-mail it to bugs@openlp.org, along with a '
|
||||
'detailed description of what you were doing when the problem '
|
||||
'occurred.'))
|
||||
self.send_report_button.setText(translate('OpenLP.ExceptionDialog', 'Send E-Mail'))
|
||||
self.save_report_button.setText(translate('OpenLP.ExceptionDialog', 'Save to File'))
|
||||
self.attach_tile_button.setText(translate('OpenLP.ExceptionDialog', 'Attach File'))
|
||||
|
@ -67,7 +67,7 @@ class ThemeScreenshotThread(QtCore.QThread):
|
||||
title = config.get('theme_%s' % theme, 'title')
|
||||
filename = config.get('theme_%s' % theme, 'filename')
|
||||
screenshot = config.get('theme_%s' % theme, 'screenshot')
|
||||
urllib.request.urlretrieve('%s%s' % (self.parent().web, screenshot),
|
||||
urllib.request.urlretrieve('%s%s' % (self.parent().themes_url, screenshot),
|
||||
os.path.join(gettempdir(), 'openlp', screenshot))
|
||||
item = QtGui.QListWidgetItem(title, self.parent().themes_list_widget)
|
||||
item.setData(QtCore.Qt.UserRole, filename)
|
||||
@ -96,6 +96,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
if self.web_access:
|
||||
files = self.web_access.read()
|
||||
self.config.read_string(files.decode())
|
||||
self.web = self.config.get('general', 'base url')
|
||||
self.songs_url = self.web + self.config.get('songs', 'directory') + '/'
|
||||
self.bibles_url = self.web + self.config.get('bibles', 'directory') + '/'
|
||||
self.themes_url = self.web + self.config.get('themes', 'directory') + '/'
|
||||
self.update_screen_list_combo()
|
||||
self.was_download_cancelled = False
|
||||
self.theme_screenshot_thread = None
|
||||
@ -341,7 +345,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
item = self.songs_list_widget.item(i)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
filename = item.data(QtCore.Qt.UserRole)
|
||||
size = self._get_file_size('%s%s' % (self.web, filename))
|
||||
size = self._get_file_size('%s%s' % (self.songs_url, filename))
|
||||
self.max_progress += size
|
||||
# Loop through the Bibles list and increase for each selected item
|
||||
iterator = QtGui.QTreeWidgetItemIterator(self.bibles_tree_widget)
|
||||
@ -350,7 +354,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
item = iterator.value()
|
||||
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
|
||||
filename = item.data(0, QtCore.Qt.UserRole)
|
||||
size = self._get_file_size('%s%s' % (self.web, filename))
|
||||
size = self._get_file_size('%s%s' % (self.bibles_url, filename))
|
||||
self.max_progress += size
|
||||
iterator += 1
|
||||
# Loop through the themes list and increase for each selected item
|
||||
@ -359,7 +363,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
item = self.themes_list_widget.item(i)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
filename = item.data(QtCore.Qt.UserRole)
|
||||
size = self._get_file_size('%s%s' % (self.web, filename))
|
||||
size = self._get_file_size('%s%s' % (self.themes_url, filename))
|
||||
self.max_progress += size
|
||||
if self.max_progress:
|
||||
# Add on 2 for plugins status setting plus a "finished" point.
|
||||
@ -435,7 +439,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
self._increment_progress_bar(self.downloading % filename, 0)
|
||||
self.previous_size = 0
|
||||
destination = os.path.join(songs_destination, str(filename))
|
||||
self.url_get_file('%s%s' % (self.web, filename), destination)
|
||||
self.url_get_file('%s%s' % (self.songs_url, filename), destination)
|
||||
# Download Bibles
|
||||
bibles_iterator = QtGui.QTreeWidgetItemIterator(
|
||||
self.bibles_tree_widget)
|
||||
@ -445,7 +449,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
bible = item.data(0, QtCore.Qt.UserRole)
|
||||
self._increment_progress_bar(self.downloading % bible, 0)
|
||||
self.previous_size = 0
|
||||
self.url_get_file('%s%s' % (self.web, bible), os.path.join(bibles_destination, bible))
|
||||
self.url_get_file('%s%s' % (self.bibles_url, bible), os.path.join(bibles_destination, bible))
|
||||
bibles_iterator += 1
|
||||
# Download themes
|
||||
for i in range(self.themes_list_widget.count()):
|
||||
@ -454,7 +458,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
theme = item.data(QtCore.Qt.UserRole)
|
||||
self._increment_progress_bar(self.downloading % theme, 0)
|
||||
self.previous_size = 0
|
||||
self.url_get_file('%s%s' % (self.web, theme), os.path.join(themes_destination, theme))
|
||||
self.url_get_file('%s%s' % (self.themes_url, theme), os.path.join(themes_destination, theme))
|
||||
# Set Default Display
|
||||
if self.display_combo_box.currentIndex() != -1:
|
||||
Settings().setValue('core/monitor', self.display_combo_box.currentIndex())
|
||||
|
@ -211,9 +211,9 @@ class Ui_FirstTimeWizard(object):
|
||||
first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
|
||||
self.title_label.setText('<span style="font-size:14pt; font-weight:600;">%s</span>' %
|
||||
translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard'))
|
||||
self.information_label.setText(translate('OpenLP.FirstTimeWizard',
|
||||
'This wizard will help you to configure OpenLP for initial use. '
|
||||
'Click the next button below to start.'))
|
||||
self.information_label.setText(
|
||||
translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
|
||||
'Click the next button below to start.'))
|
||||
self.plugin_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Activate required Plugins'))
|
||||
self.plugin_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select the Plugins you wish to use. '))
|
||||
self.songs_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Songs'))
|
||||
|
@ -63,7 +63,6 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog, FormattingTagCont
|
||||
self.services = FormattingTagController()
|
||||
self.tag_table_widget.itemSelectionChanged.connect(self.on_row_selected)
|
||||
self.new_button.clicked.connect(self.on_new_clicked)
|
||||
#self.save_button.clicked.connect(self.on_saved_clicked)
|
||||
self.delete_button.clicked.connect(self.on_delete_clicked)
|
||||
self.tag_table_widget.currentCellChanged.connect(self.on_current_cell_changed)
|
||||
self.button_box.rejected.connect(self.close)
|
||||
@ -202,5 +201,4 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog, FormattingTagCont
|
||||
if errors:
|
||||
QtGui.QMessageBox.warning(self, translate('OpenLP.FormattingTagForm', 'Validation Error'), errors,
|
||||
QtGui.QMessageBox.Ok)
|
||||
#self.tag_table_widget.selectRow(pre_row - 1)
|
||||
self.tag_table_widget.resizeRowsToContents()
|
||||
|
@ -168,8 +168,10 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties):
|
||||
"""
|
||||
if enabled:
|
||||
self.setAutoFillBackground(False)
|
||||
self.setStyleSheet("QGraphicsView {background: transparent; border: 0px;}")
|
||||
else:
|
||||
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, False)
|
||||
self.setStyleSheet("QGraphicsView {}")
|
||||
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, enabled)
|
||||
self.repaint()
|
||||
|
||||
@ -350,7 +352,6 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties):
|
||||
self.hide_display(self.hide_mode)
|
||||
# Only continue if the visibility wasn't changed during method call.
|
||||
elif was_visible == self.isVisible():
|
||||
|
||||
# Single screen active
|
||||
if self.screens.display_count == 1:
|
||||
# Only make visible if setting enabled.
|
||||
|
@ -56,29 +56,27 @@ from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
MEDIA_MANAGER_STYLE = """
|
||||
QToolBox {
|
||||
QToolBox {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
QToolBox::tab {
|
||||
}
|
||||
QToolBox::tab {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 palette(button), stop: 0.5 palette(button),
|
||||
stop: 1.0 palette(mid));
|
||||
border: 1px groove palette(mid);
|
||||
border-radius: 5px;
|
||||
}
|
||||
QToolBox::tab:selected {
|
||||
stop: 0 palette(button), stop: 1.0 palette(mid));
|
||||
border: 1px solid palette(mid);
|
||||
border-radius: 3px;
|
||||
}
|
||||
QToolBox::tab:selected {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 palette(light), stop: 0.5 palette(midlight),
|
||||
stop: 1.0 palette(dark));
|
||||
border: 1px groove palette(dark);
|
||||
stop: 0 palette(light), stop: 1.0 palette(button));
|
||||
border: 1px solid palette(mid);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
PROGRESSBAR_STYLE = """
|
||||
QProgressBar{
|
||||
height: 10px;
|
||||
}
|
||||
QProgressBar{
|
||||
height: 10px;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@ -369,7 +367,7 @@ class Ui_MainWindow(object):
|
||||
self.settings_menu.setTitle(translate('OpenLP.MainWindow', '&Settings'))
|
||||
self.settings_language_menu.setTitle(translate('OpenLP.MainWindow', '&Language'))
|
||||
self.help_menu.setTitle(translate('OpenLP.MainWindow', '&Help'))
|
||||
self.media_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Media Manager'))
|
||||
self.media_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Library'))
|
||||
self.service_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Service Manager'))
|
||||
self.theme_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Theme Manager'))
|
||||
self.file_new_item.setText(translate('OpenLP.MainWindow', '&New'))
|
||||
@ -396,12 +394,12 @@ class Ui_MainWindow(object):
|
||||
self.settings_shortcuts_item.setText(translate('OpenLP.MainWindow', 'Configure &Shortcuts...'))
|
||||
self.formatting_tag_item.setText(translate('OpenLP.MainWindow', 'Configure &Formatting Tags...'))
|
||||
self.settings_configure_item.setText(translate('OpenLP.MainWindow', '&Configure OpenLP...'))
|
||||
self.settings_export_item.setStatusTip(translate('OpenLP.MainWindow',
|
||||
'Export OpenLP settings to a specified *.config file'))
|
||||
self.settings_export_item.setStatusTip(
|
||||
translate('OpenLP.MainWindow', 'Export OpenLP settings to a specified *.config file'))
|
||||
self.settings_export_item.setText(translate('OpenLP.MainWindow', 'Settings'))
|
||||
self.settings_import_item.setStatusTip(translate('OpenLP.MainWindow',
|
||||
'Import OpenLP settings from a specified *.config file previously '
|
||||
'exported on this or another machine'))
|
||||
self.settings_import_item.setStatusTip(
|
||||
translate('OpenLP.MainWindow', 'Import OpenLP settings from a specified *.config file previously '
|
||||
'exported on this or another machine'))
|
||||
self.settings_import_item.setText(translate('OpenLP.MainWindow', 'Settings'))
|
||||
self.view_media_manager_item.setText(translate('OpenLP.MainWindow', '&Media Manager'))
|
||||
self.view_media_manager_item.setToolTip(translate('OpenLP.MainWindow', 'Toggle Media Manager'))
|
||||
@ -598,13 +596,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
self.live_controller.display.setFocus()
|
||||
self.activateWindow()
|
||||
if self.arguments:
|
||||
args = []
|
||||
for a in self.arguments:
|
||||
args.extend([a])
|
||||
filename = args[0]
|
||||
if not isinstance(filename, str):
|
||||
filename = str(filename, sys.getfilesystemencoding())
|
||||
self.service_manager_contents.load_file(filename)
|
||||
self.open_cmd_line_files()
|
||||
elif Settings().value(self.general_settings_section + '/auto open'):
|
||||
self.service_manager_contents.load_Last_file()
|
||||
self.timer_version_id = self.startTimer(1000)
|
||||
@ -868,7 +860,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
section = 'general'
|
||||
section_key = section + "/" + key
|
||||
# Make sure it's a valid section for us.
|
||||
if not section in setting_sections:
|
||||
if section not in setting_sections:
|
||||
continue
|
||||
# We have a good file, import it.
|
||||
for section_key in import_keys:
|
||||
@ -1364,3 +1356,17 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
if self.new_data_path == AppLocation.get_directory(AppLocation.DataDir):
|
||||
settings.remove('advanced/data path')
|
||||
self.application.set_normal_cursor()
|
||||
|
||||
def open_cmd_line_files(self):
|
||||
"""
|
||||
Open files passed in through command line arguments
|
||||
"""
|
||||
args = []
|
||||
for a in self.arguments:
|
||||
args.extend([a])
|
||||
for arg in args:
|
||||
filename = arg
|
||||
if not isinstance(filename, str):
|
||||
filename = str(filename, sys.getfilesystemencoding())
|
||||
if filename.endswith(('.osz', '.oszl')):
|
||||
self.service_manager_contents.load_file(filename)
|
||||
|
@ -35,7 +35,7 @@ from openlp.core.common import Settings
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
log = logging.getLogger(__name__+'.__init__')
|
||||
log = logging.getLogger(__name__ + '.__init__')
|
||||
|
||||
|
||||
class MediaState(object):
|
||||
|
@ -137,7 +137,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
for player in list(self.media_players.values()):
|
||||
if player.is_active:
|
||||
for item in player.audio_extensions_list:
|
||||
if not item in self.audio_extensions_list:
|
||||
if item not in self.audio_extensions_list:
|
||||
self.audio_extensions_list.append(item)
|
||||
suffix_list.append(item[2:])
|
||||
self.video_extensions_list = []
|
||||
@ -184,8 +184,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
return False
|
||||
saved_players, overridden_player = get_media_players()
|
||||
invalid_media_players = \
|
||||
[mediaPlayer for mediaPlayer in saved_players if not mediaPlayer in self.media_players or
|
||||
not self.media_players[mediaPlayer].check_available()]
|
||||
[media_player for media_player in saved_players if media_player not in self.media_players or
|
||||
not self.media_players[media_player].check_available()]
|
||||
if invalid_media_players:
|
||||
for invalidPlayer in invalid_media_players:
|
||||
saved_players.remove(invalidPlayer)
|
||||
@ -506,7 +506,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
else:
|
||||
self.media_volume(controller, controller.media_info.volume)
|
||||
if status:
|
||||
display.frame.evaluateJavaScript('show_blank("desktop");')
|
||||
if not controller.media_info.is_background:
|
||||
display.frame.evaluateJavaScript('show_blank("desktop");')
|
||||
self.current_media_players[controller.controller_type].set_visible(display, True)
|
||||
# Flash needs to be played and will not AutoPlay
|
||||
if controller.media_info.is_flash:
|
||||
@ -517,7 +518,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
controller.mediabar.actions['playbackPause'].setVisible(True)
|
||||
controller.mediabar.actions['playbackStop'].setVisible(True)
|
||||
if controller.is_live:
|
||||
if controller.hide_menu.defaultAction().isChecked():
|
||||
if controller.hide_menu.defaultAction().isChecked() and not controller.media_info.is_background:
|
||||
controller.hide_menu.defaultAction().trigger()
|
||||
# Start Timer for ui updates
|
||||
if not self.timer.isActive():
|
||||
|
66
openlp/core/ui/media/vendor/vlc.py
vendored
66
openlp/core/ui/media/vendor/vlc.py
vendored
@ -48,13 +48,13 @@ import sys
|
||||
from inspect import getargspec
|
||||
|
||||
__version__ = "N/A"
|
||||
build_date = "Mon Apr 1 23:47:38 2013"
|
||||
build_date = "Tue Jul 2 10:35:53 2013"
|
||||
|
||||
if sys.version_info[0] > 2:
|
||||
str = str
|
||||
str = str
|
||||
unicode = str
|
||||
bytes = bytes
|
||||
str = (str, bytes)
|
||||
basestring = (str, bytes)
|
||||
PYTHON3 = True
|
||||
def str_to_bytes(s):
|
||||
"""Translate string or bytes to bytes.
|
||||
@ -73,14 +73,14 @@ if sys.version_info[0] > 2:
|
||||
return b
|
||||
else:
|
||||
str = str
|
||||
str = str
|
||||
unicode = unicode
|
||||
bytes = str
|
||||
str = str
|
||||
basestring = basestring
|
||||
PYTHON3 = False
|
||||
def str_to_bytes(s):
|
||||
"""Translate string or bytes to bytes.
|
||||
"""
|
||||
if isinstance(s, str):
|
||||
if isinstance(s, unicode):
|
||||
return s.encode(sys.getfilesystemencoding())
|
||||
else:
|
||||
return s
|
||||
@ -89,7 +89,7 @@ else:
|
||||
"""Translate bytes to unicode string.
|
||||
"""
|
||||
if isinstance(b, str):
|
||||
return str(b, sys.getfilesystemencoding())
|
||||
return unicode(b, sys.getfilesystemencoding())
|
||||
else:
|
||||
return b
|
||||
|
||||
@ -110,7 +110,7 @@ def find_lib():
|
||||
p = find_library('libvlc.dll')
|
||||
if p is None:
|
||||
try: # some registry settings
|
||||
import winreg as w # leaner than win32api, win32con
|
||||
import _winreg as w # leaner than win32api, win32con
|
||||
for r in w.HKEY_LOCAL_MACHINE, w.HKEY_CURRENT_USER:
|
||||
try:
|
||||
r = w.OpenKey(r, 'Software\\VideoLAN\\VLC')
|
||||
@ -168,7 +168,7 @@ class VLCException(Exception):
|
||||
pass
|
||||
|
||||
try:
|
||||
_Ints = (int, int)
|
||||
_Ints = (int, long)
|
||||
except NameError: # no long in Python 3+
|
||||
_Ints = int
|
||||
_Seqs = (list, tuple)
|
||||
@ -327,6 +327,9 @@ class _Enum(ctypes.c_uint):
|
||||
n = self._enum_names_.get(self.value, '') or ('FIXME_(%r)' % (self.value,))
|
||||
return '.'.join((self.__class__.__name__, n))
|
||||
|
||||
def __hash__(self):
|
||||
return self.value
|
||||
|
||||
def __repr__(self):
|
||||
return '.'.join((self.__class__.__module__, self.__str__()))
|
||||
|
||||
@ -1294,7 +1297,7 @@ class Instance(_Ctype):
|
||||
i = args[0]
|
||||
if isinstance(i, _Ints):
|
||||
return _Constructor(cls, i)
|
||||
elif isinstance(i, str):
|
||||
elif isinstance(i, basestring):
|
||||
args = i.strip().split()
|
||||
elif isinstance(i, _Seqs):
|
||||
args = i
|
||||
@ -2078,7 +2081,7 @@ class MediaList(_Ctype):
|
||||
@param mrl: a media instance or a MRL.
|
||||
@return: 0 on success, -1 if the media list is read-only.
|
||||
"""
|
||||
if isinstance(mrl, str):
|
||||
if isinstance(mrl, basestring):
|
||||
mrl = (self.get_instance() or get_default_instance()).media_new(mrl)
|
||||
return libvlc_media_list_add_media(self, mrl)
|
||||
|
||||
@ -3351,6 +3354,39 @@ def libvlc_event_type_name(event_type):
|
||||
ctypes.c_char_p, ctypes.c_uint)
|
||||
return f(event_type)
|
||||
|
||||
def libvlc_log_get_context(ctx):
|
||||
'''Gets debugging informations about a log message: the name of the VLC module
|
||||
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 line number will similarly be zero if unknown.
|
||||
@param ctx: message context (as passed to the @ref libvlc_log_cb callback).
|
||||
@return: module module name storage (or NULL), file source code file name storage (or NULL), line source code file line number storage (or NULL).
|
||||
@version: LibVLC 2.1.0 or later.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_get_context', None) or \
|
||||
_Cfunction('libvlc_log_get_context', ((1,), (2,), (2,), (2,),), None,
|
||||
None, Log_ptr, ListPOINTER(ctypes.c_char_p), ListPOINTER(ctypes.c_char_p), ctypes.POINTER(ctypes.c_uint))
|
||||
return f(ctx)
|
||||
|
||||
def libvlc_log_get_object(ctx, id):
|
||||
'''Gets VLC object informations about a log message: the type name of the VLC
|
||||
object emitting the message, the object header if any and a temporaly-unique
|
||||
object identifier. These informations are mainly meant for B{manual}
|
||||
troubleshooting.
|
||||
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
|
||||
is used to distinguish for VLM inputs.
|
||||
The returned object ID will be zero if the message is not associated with
|
||||
any VLC object.
|
||||
@param ctx: message context (as passed to the @ref libvlc_log_cb callback).
|
||||
@return: name object name storage (or NULL), header object header (or NULL), line source code file line number storage (or NULL).
|
||||
@version: LibVLC 2.1.0 or later.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_get_object', None) or \
|
||||
_Cfunction('libvlc_log_get_object', ((1,), (2,), (2,), (1,),), None,
|
||||
None, Log_ptr, ListPOINTER(ctypes.c_char_p), ListPOINTER(ctypes.c_char_p), ctypes.POINTER(ctypes.c_uint))
|
||||
return f(ctx, id)
|
||||
|
||||
def libvlc_log_unset(p_instance):
|
||||
'''Unsets the logging callback for a LibVLC instance. This is rarely needed:
|
||||
the callback is implicitly unset when the instance is destroyed.
|
||||
@ -5827,7 +5863,7 @@ def libvlc_vlm_get_event_manager(p_instance):
|
||||
# libvlc_printerr
|
||||
# libvlc_set_exit_handler
|
||||
|
||||
# 15 function(s) not wrapped as methods:
|
||||
# 17 function(s) not wrapped as methods:
|
||||
# libvlc_audio_output_device_list_release
|
||||
# libvlc_audio_output_list_release
|
||||
# libvlc_clearerr
|
||||
@ -5838,6 +5874,8 @@ def libvlc_vlm_get_event_manager(p_instance):
|
||||
# libvlc_get_changeset
|
||||
# libvlc_get_compiler
|
||||
# libvlc_get_version
|
||||
# libvlc_log_get_context
|
||||
# libvlc_log_get_object
|
||||
# libvlc_media_tracks_release
|
||||
# libvlc_module_description_list_release
|
||||
# libvlc_new
|
||||
@ -5910,9 +5948,9 @@ def debug_callback(event, *args, **kwds):
|
||||
'''
|
||||
l = ['event %s' % (event.type,)]
|
||||
if args:
|
||||
l.extend(list(map(str, args)))
|
||||
l.extend(map(str, args))
|
||||
if kwds:
|
||||
l.extend(sorted('%s=%s' % t for t in list(kwds.items())))
|
||||
l.extend(sorted('%s=%s' % t for t in kwds.items()))
|
||||
print('Debug callback (%s)' % ', '.join(l))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -174,34 +174,11 @@ FLASH_HTML = """
|
||||
<div id="flash" class="size" style="visibility:hidden"></div>
|
||||
"""
|
||||
|
||||
VIDEO_EXT = [
|
||||
'*.3gp',
|
||||
'*.3gpp',
|
||||
'*.3g2',
|
||||
'*.3gpp2',
|
||||
'*.aac',
|
||||
'*.flv',
|
||||
'*.f4a',
|
||||
'*.f4b',
|
||||
'*.f4p',
|
||||
'*.f4v',
|
||||
'*.mov',
|
||||
'*.m4a',
|
||||
'*.m4b',
|
||||
'*.m4p',
|
||||
'*.m4v',
|
||||
'*.mkv',
|
||||
'*.mp4',
|
||||
'*.ogv',
|
||||
'*.webm',
|
||||
'*.mpg', '*.wmv', '*.mpeg', '*.avi',
|
||||
'*.swf'
|
||||
]
|
||||
VIDEO_EXT = ['*.3gp', '*.3gpp', '*.3g2', '*.3gpp2', '*.aac', '*.flv', '*.f4a', '*.f4b', '*.f4p', '*.f4v', '*.mov',
|
||||
'*.m4a', '*.m4b', '*.m4p', '*.m4v', '*.mkv', '*.mp4', '*.ogv', '*.webm', '*.mpg', '*.wmv', '*.mpeg',
|
||||
'*.avi', '*.swf']
|
||||
|
||||
AUDIO_EXT = [
|
||||
'*.mp3',
|
||||
'*.ogg'
|
||||
]
|
||||
AUDIO_EXT = ['*.mp3', '*.ogg']
|
||||
|
||||
|
||||
class WebkitPlayer(MediaPlayer):
|
||||
@ -411,10 +388,9 @@ class WebkitPlayer(MediaPlayer):
|
||||
"""
|
||||
Return some information about this player
|
||||
"""
|
||||
return(translate('Media.player', 'Webkit is a media player which runs '
|
||||
'inside a web browser. This player allows text over video to be '
|
||||
'rendered.') +
|
||||
'<br/> <strong>' + translate('Media.player', 'Audio') +
|
||||
'</strong><br/>' + str(AUDIO_EXT) + '<br/><strong>' +
|
||||
translate('Media.player', 'Video') + '</strong><br/>' +
|
||||
str(VIDEO_EXT) + '<br/>')
|
||||
part1 = translate('Media.player', 'Webkit is a media player which runs inside a web browser. This player '
|
||||
'allows text over video to be rendered.')
|
||||
part2 = translate('Media.player', 'Audio')
|
||||
part3 = translate('Media.player', 'Video')
|
||||
return part1 + '<br/> <strong>' + part2 + '</strong><br/>' + str(AUDIO_EXT) + '<br/><strong>' + part3 + \
|
||||
'</strong><br/>' + str(VIDEO_EXT) + '<br/>'
|
||||
|
@ -234,6 +234,9 @@ class Ui_ServiceManager(object):
|
||||
self.menu = QtGui.QMenu()
|
||||
self.edit_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Edit Item'),
|
||||
icon=':/general/general_edit.png', triggers=self.remote_edit)
|
||||
self.rename_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Rename...'),
|
||||
icon=':/general/general_edit.png',
|
||||
triggers=self.on_service_item_rename)
|
||||
self.maintain_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Reorder Item'),
|
||||
icon=':/general/general_edit.png',
|
||||
triggers=self.on_service_item_edit_form)
|
||||
@ -399,7 +402,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
||||
:param suffix_list: New Suffix's to be supported
|
||||
"""
|
||||
for suffix in suffix_list:
|
||||
if not suffix in self.suffixes:
|
||||
if suffix not in self.suffixes:
|
||||
self.suffixes.append(suffix)
|
||||
|
||||
def on_new_service_clicked(self, field=None):
|
||||
@ -629,7 +632,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
||||
for item in self.service_items:
|
||||
self.main_window.increment_progress_bar()
|
||||
service_item = item['service_item'].get_service_repr(self._save_lite)
|
||||
#TODO: check for file item on save.
|
||||
# TODO: check for file item on save.
|
||||
service.append({'serviceitem': service_item})
|
||||
self.main_window.increment_progress_bar()
|
||||
service_content = json.dumps(service)
|
||||
@ -754,8 +757,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
||||
items = json.load(file_to)
|
||||
else:
|
||||
critical_error_message_box(message=translate('OpenLP.ServiceManager',
|
||||
'The service file you are trying to open is in an old format.\n '
|
||||
'Please save it using OpenLP 2.0.2 or greater.'))
|
||||
'The service file you are trying to open is in an old '
|
||||
'format.\n Please save it using OpenLP 2.0.2 or '
|
||||
'greater.'))
|
||||
return
|
||||
file_to.close()
|
||||
self.new_file()
|
||||
@ -848,6 +852,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
||||
pos = item.data(0, QtCore.Qt.UserRole)
|
||||
service_item = self.service_items[pos - 1]
|
||||
self.edit_action.setVisible(False)
|
||||
self.rename_action.setVisible(False)
|
||||
self.create_custom_action.setVisible(False)
|
||||
self.maintain_action.setVisible(False)
|
||||
self.notes_action.setVisible(False)
|
||||
@ -855,6 +860,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
||||
self.auto_start_action.setVisible(False)
|
||||
if service_item['service_item'].is_capable(ItemCapabilities.CanEdit) and service_item['service_item'].edit_id:
|
||||
self.edit_action.setVisible(True)
|
||||
if service_item['service_item'].is_capable(ItemCapabilities.CanEditTitle):
|
||||
self.rename_action.setVisible(True)
|
||||
if service_item['service_item'].is_capable(ItemCapabilities.CanMaintain):
|
||||
self.maintain_action.setVisible(True)
|
||||
if item.parent() is None:
|
||||
@ -1482,6 +1489,24 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
||||
if new_item:
|
||||
self.add_service_item(new_item, replace=True)
|
||||
|
||||
def on_service_item_rename(self, field=None):
|
||||
"""
|
||||
Opens a dialog to rename the service item.
|
||||
|
||||
:param field: Not used, but PyQt needs this.
|
||||
"""
|
||||
item = self.find_service_item()[0]
|
||||
if not self.service_items[item]['service_item'].is_capable(ItemCapabilities.CanEditTitle):
|
||||
return
|
||||
title = self.service_items[item]['service_item'].title
|
||||
title, ok = QtGui.QInputDialog.getText(self, translate('OpenLP.ServiceManager', 'Rename item title'),
|
||||
translate('OpenLP.ServiceManager', 'Title:'),
|
||||
QtGui.QLineEdit.Normal, self.trUtf8(title))
|
||||
if ok:
|
||||
self.service_items[item]['service_item'].title = title
|
||||
self.repaint_service_list(item, -1)
|
||||
self.set_modified()
|
||||
|
||||
def create_custom(self, field=None):
|
||||
"""
|
||||
Saves the current text item as a custom slide
|
||||
|
@ -150,5 +150,5 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
|
||||
|
||||
:param function: The function to be called
|
||||
"""
|
||||
if not function in self.processes:
|
||||
if function not in self.processes:
|
||||
self.processes.append(function)
|
||||
|
@ -495,14 +495,14 @@ class SlideController(DisplayController, RegistryProperties):
|
||||
self.on_theme_display(False)
|
||||
self.on_hide_display(False)
|
||||
|
||||
def service_previous(self):
|
||||
def service_previous(self, field=None):
|
||||
"""
|
||||
Live event to select the previous service item from the service manager.
|
||||
"""
|
||||
self.keypress_queue.append(ServiceItemAction.Previous)
|
||||
self._process_queue()
|
||||
|
||||
def service_next(self):
|
||||
def service_next(self, field=None):
|
||||
"""
|
||||
Live event to select the next service item from the service manager.
|
||||
"""
|
||||
@ -1039,7 +1039,6 @@ class SlideController(DisplayController, RegistryProperties):
|
||||
"""
|
||||
self.preview_widget.change_slide(row)
|
||||
self.update_preview()
|
||||
Registry().execute('slidecontroller_%s_changed' % self.type_prefix, row)
|
||||
|
||||
def update_preview(self):
|
||||
"""
|
||||
|
@ -44,7 +44,6 @@ class Ui_ThemeLayoutDialog(object):
|
||||
Set up the UI
|
||||
"""
|
||||
themeLayoutDialog.setObjectName('themeLayoutDialogDialog')
|
||||
#themeLayoutDialog.resize(300, 200)
|
||||
self.preview_layout = QtGui.QVBoxLayout(themeLayoutDialog)
|
||||
self.preview_layout.setObjectName('preview_layout')
|
||||
self.preview_area = QtGui.QWidget(themeLayoutDialog)
|
||||
|
@ -114,17 +114,19 @@ class ThemesTab(SettingsTab):
|
||||
self.global_group_box.setTitle(translate('OpenLP.ThemesTab', 'Global Theme'))
|
||||
self.level_group_box.setTitle(translate('OpenLP.ThemesTab', 'Theme Level'))
|
||||
self.song_level_radio_button.setText(translate('OpenLP.ThemesTab', 'S&ong Level'))
|
||||
self.song_level_label.setText(translate('OpenLP.ThemesTab', 'Use the theme from each song '
|
||||
'in the database. If a song doesn\'t have a theme associated with '
|
||||
'it, then use the service\'s theme. If the service doesn\'t have '
|
||||
'a theme, then use the global theme.'))
|
||||
self.song_level_label.setText(
|
||||
translate('OpenLP.ThemesTab', 'Use the theme from each song in the database. If a song doesn\'t have a '
|
||||
'theme associated with it, then use the service\'s theme. If the service '
|
||||
'doesn\'t have a theme, then use the global theme.'))
|
||||
self.service_level_radio_button.setText(translate('OpenLP.ThemesTab', '&Service Level'))
|
||||
self.service_level_label.setText(translate('OpenLP.ThemesTab', 'Use the theme from the service, '
|
||||
'overriding any of the individual songs\' themes. If the '
|
||||
'service doesn\'t have a theme, then use the global theme.'))
|
||||
self.service_level_label.setText(
|
||||
translate('OpenLP.ThemesTab', 'Use the theme from the service, overriding any of the individual '
|
||||
'songs\' themes. If the service doesn\'t have a theme, then use the global '
|
||||
'theme.'))
|
||||
self.global_level_radio_button.setText(translate('OpenLP.ThemesTab', '&Global Level'))
|
||||
self.global_level_label.setText(translate('OpenLP.ThemesTab', 'Use the global theme, overriding '
|
||||
'any themes associated with either the service or the songs.'))
|
||||
self.global_level_label.setText(translate('OpenLP.ThemesTab', 'Use the global theme, overriding any themes '
|
||||
'associated with either the service or the '
|
||||
'songs.'))
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
|
@ -56,7 +56,7 @@ if sys.platform != 'win32' and sys.platform != 'darwin':
|
||||
|
||||
from openlp.core.common import translate
|
||||
|
||||
log = logging.getLogger(__name__+'.__init__')
|
||||
log = logging.getLogger(__name__ + '.__init__')
|
||||
|
||||
APPLICATION_VERSION = {}
|
||||
IMAGES_FILTER = None
|
||||
|
@ -74,7 +74,7 @@ class LanguageManager(object):
|
||||
log.debug('Translation files: %s', 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_".
|
||||
file_names = [file_ for file_ in file_names if not file_.startswith('qt_')]
|
||||
return list(map(trans_dir.filePath, file_names))
|
||||
|
@ -207,12 +207,12 @@ class AlertsPlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('AlertsPlugin', 'Alert', 'name singular'),
|
||||
'plural': translate('AlertsPlugin', 'Alerts', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('AlertsPlugin', 'Alerts', 'container title')
|
||||
}
|
||||
|
@ -88,8 +88,6 @@ class BiblePlugin(Plugin):
|
||||
self.import_bible_item.setVisible(True)
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.add_action(self.import_bible_item, UiStrings().Import)
|
||||
# Do not add the action to the list yet.
|
||||
#action_list.add_action(self.export_bible_item, UiStrings().Export)
|
||||
# Set to invisible until we can export bibles
|
||||
self.export_bible_item.setVisible(False)
|
||||
self.tools_upgrade_item.setVisible(bool(self.manager.old_bible_databases))
|
||||
@ -104,7 +102,6 @@ class BiblePlugin(Plugin):
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.remove_action(self.import_bible_item, UiStrings().Import)
|
||||
self.import_bible_item.setVisible(False)
|
||||
#action_list.remove_action(self.export_bible_item, UiStrings().Export)
|
||||
self.export_bible_item.setVisible(False)
|
||||
|
||||
def app_startup(self):
|
||||
@ -115,19 +112,27 @@ class BiblePlugin(Plugin):
|
||||
if self.manager.old_bible_databases:
|
||||
if QtGui.QMessageBox.information(
|
||||
self.main_window, translate('OpenLP', 'Information'),
|
||||
translate('OpenLP', 'Bible format has changed.\nYou have to upgrade your existing Bibles.\n'
|
||||
'Should OpenLP upgrade now?'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) == \
|
||||
translate('OpenLP', 'Bible format has changed.\nYou have to upgrade your '
|
||||
'existing Bibles.\nShould OpenLP upgrade now?'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) == \
|
||||
QtGui.QMessageBox.Yes:
|
||||
self.on_tools_upgrade_Item_triggered()
|
||||
|
||||
def add_import_menu_item(self, import_menu):
|
||||
"""
|
||||
|
||||
:param import_menu:
|
||||
"""
|
||||
self.import_bible_item = create_action(import_menu, 'importBibleItem',
|
||||
text=translate('BiblesPlugin', '&Bible'), visible=False,
|
||||
triggers=self.on_bible_import_click)
|
||||
import_menu.addAction(self.import_bible_item)
|
||||
|
||||
def add_export_menu_Item(self, export_menu):
|
||||
def add_export_menu_item(self, export_menu):
|
||||
"""
|
||||
|
||||
:param export_menu:
|
||||
"""
|
||||
self.export_bible_item = create_action(export_menu, 'exportBibleItem',
|
||||
text=translate('BiblesPlugin', '&Bible'), visible=False)
|
||||
export_menu.addAction(self.export_bible_item)
|
||||
@ -190,12 +195,12 @@ class BiblePlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('BiblesPlugin', 'Bible', 'name singular'),
|
||||
'plural': translate('BiblesPlugin', 'Bibles', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('BiblesPlugin', 'Bibles', 'container title')
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||
Set up the UI for the bible wizard.
|
||||
"""
|
||||
super(BibleUpgradeForm, self).setupUi(image)
|
||||
Registry().execute('openlp_stop_wizard', self.stop_import)
|
||||
Registry().register_function('openlp_stop_wizard', self.stop_import)
|
||||
|
||||
def stop_import(self):
|
||||
"""
|
||||
|
@ -32,9 +32,11 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore
|
||||
from sqlalchemy import Column, ForeignKey, Table, or_, types, func
|
||||
from sqlalchemy.exc import OperationalError
|
||||
from sqlalchemy.orm import class_mapper, mapper, relation
|
||||
from sqlalchemy.orm.exc import UnmappedClassError
|
||||
|
||||
@ -154,7 +156,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
if 'path' in kwargs:
|
||||
self.path = kwargs['path']
|
||||
self.wizard = None
|
||||
Registry().execute('openlp_stop_wizard', self.stop_import)
|
||||
Registry().register_function('openlp_stop_wizard', self.stop_import)
|
||||
|
||||
def stop_import(self):
|
||||
"""
|
||||
@ -191,7 +193,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
:param testament: *Defaults to 1.* The testament_reference_id from
|
||||
bibles_resources.sqlite of the testament this book belongs to.
|
||||
"""
|
||||
log.debug('BibleDB.create_book("%s", "%s")', name, bk_ref_id)
|
||||
log.debug('BibleDB.create_book("%s", "%s")' % (name, bk_ref_id))
|
||||
book = Book.populate(name=name, book_reference_id=bk_ref_id, testament_reference_id=testament)
|
||||
self.save_object(book)
|
||||
return book
|
||||
@ -202,7 +204,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
|
||||
:param book: The book object
|
||||
"""
|
||||
log.debug('BibleDB.update_book("%s")', book.name)
|
||||
log.debug('BibleDB.update_book("%s")' % book.name)
|
||||
return self.save_object(book)
|
||||
|
||||
def delete_book(self, db_book):
|
||||
@ -211,7 +213,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
|
||||
:param db_book: The book object.
|
||||
"""
|
||||
log.debug('BibleDB.delete_book("%s")', db_book.name)
|
||||
log.debug('BibleDB.delete_book("%s")' % db_book.name)
|
||||
if self.delete_object(Book, db_book.id):
|
||||
return True
|
||||
return False
|
||||
@ -225,7 +227,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
:param text_list: A dict of the verses to be inserted. The key is the verse number, and the value is the
|
||||
verse text.
|
||||
"""
|
||||
log.debug('BibleDBcreate_chapter("%s", "%s")', book_id, chapter)
|
||||
log.debug('BibleDBcreate_chapter("%s", "%s")' % (book_id, chapter))
|
||||
# Text list has book and chapter as first two elements of the array.
|
||||
for verse_number, verse_text in text_list.items():
|
||||
verse = Verse.populate(
|
||||
@ -235,7 +237,12 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
text=verse_text
|
||||
)
|
||||
self.session.add(verse)
|
||||
self.session.commit()
|
||||
try:
|
||||
self.session.commit()
|
||||
except OperationalError:
|
||||
# Wait 10ms and try again (lp#1154467)
|
||||
time.sleep(0.01)
|
||||
self.session.commit()
|
||||
|
||||
def create_verse(self, book_id, chapter, verse, text):
|
||||
"""
|
||||
@ -267,7 +274,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
"""
|
||||
if not isinstance(value, str):
|
||||
value = str(value)
|
||||
log.debug('BibleDB.save_meta("%s/%s")', key, value)
|
||||
log.debug('BibleDB.save_meta("%s/%s")' % (key, value))
|
||||
meta = self.get_object(BibleMeta, key)
|
||||
if meta:
|
||||
meta.value = value
|
||||
@ -281,7 +288,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
|
||||
:param book: The name of the book to return.
|
||||
"""
|
||||
log.debug('BibleDB.get_book("%s")', book)
|
||||
log.debug('BibleDB.get_book("%s")' % book)
|
||||
return self.get_object_filtered(Book, Book.name.like(book + '%'))
|
||||
|
||||
def get_books(self):
|
||||
@ -292,17 +299,17 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
log.debug('BibleDB.get_books()')
|
||||
return self.get_all_objects(Book, order_by_ref=Book.id)
|
||||
|
||||
def get_book_by_book_ref_id(self, id):
|
||||
def get_book_by_book_ref_id(self, ref_id):
|
||||
"""
|
||||
Return a book object from the database.
|
||||
|
||||
:param id: The reference id of the book to return.
|
||||
:param ref_id: The reference id of the book to return.
|
||||
"""
|
||||
log.debug('BibleDB.get_book_by_book_ref_id("%s")', id)
|
||||
return self.get_object_filtered(Book, Book.book_reference_id.like(id))
|
||||
log.debug('BibleDB.get_book_by_book_ref_id("%s")' % ref_id)
|
||||
return self.get_object_filtered(Book, Book.book_reference_id.like(ref_id))
|
||||
|
||||
def get_book_ref_id_by_name(self, book, maxbooks, language_id=None):
|
||||
log.debug('BibleDB.get_book_ref_id_by_name:("%s", "%s")', book, language_id)
|
||||
log.debug('BibleDB.get_book_ref_id_by_name:("%s", "%s")' % (book, language_id))
|
||||
book_id = None
|
||||
if BiblesResourcesDB.get_book(book, True):
|
||||
book_temp = BiblesResourcesDB.get_book(book, True)
|
||||
@ -328,7 +335,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
:param book: The name of the book, according to the selected language.
|
||||
:param language_selection: The language selection the user has chosen in the settings section of the Bible.
|
||||
"""
|
||||
log.debug('get_book_ref_id_by_localised_name("%s", "%s")', book, language_selection)
|
||||
log.debug('get_book_ref_id_by_localised_name("%s", "%s")' % (book, language_selection))
|
||||
from openlp.plugins.bibles.lib import LanguageSelection, BibleStrings
|
||||
book_names = BibleStrings().BookNames
|
||||
# escape reserved characters
|
||||
@ -376,14 +383,14 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
[(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
|
||||
:param show_error:
|
||||
"""
|
||||
log.debug('BibleDB.get_verses("%s")', reference_list)
|
||||
log.debug('BibleDB.get_verses("%s")' % reference_list)
|
||||
verse_list = []
|
||||
book_error = False
|
||||
for book_id, chapter, start_verse, end_verse in reference_list:
|
||||
db_book = self.get_book_by_book_ref_id(book_id)
|
||||
if db_book:
|
||||
book_id = db_book.book_reference_id
|
||||
log.debug('Book name corrected to "%s"', db_book.name)
|
||||
log.debug('Book name corrected to "%s"' % db_book.name)
|
||||
if end_verse == -1:
|
||||
end_verse = self.get_verse_count(book_id, chapter)
|
||||
verses = self.session.query(Verse) \
|
||||
@ -395,7 +402,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
.all()
|
||||
verse_list.extend(verses)
|
||||
else:
|
||||
log.debug('OpenLP failed to find book with id "%s"', book_id)
|
||||
log.debug('OpenLP failed to find book with id "%s"' % book_id)
|
||||
book_error = True
|
||||
if book_error and show_error:
|
||||
critical_error_message_box(
|
||||
@ -414,7 +421,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
contains spaces, it will split apart and AND'd on the list of
|
||||
values.
|
||||
"""
|
||||
log.debug('BibleDB.verse_search("%s")', text)
|
||||
log.debug('BibleDB.verse_search("%s")' % text)
|
||||
verses = self.session.query(Verse)
|
||||
if text.find(',') > -1:
|
||||
keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(',')]
|
||||
@ -433,7 +440,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
|
||||
:param book: The book object to get the chapter count for.
|
||||
"""
|
||||
log.debug('BibleDB.get_chapter_count("%s")', book.name)
|
||||
log.debug('BibleDB.get_chapter_count("%s")' % book.name)
|
||||
count = self.session.query(func.max(Verse.chapter)).join(Book).filter(
|
||||
Book.book_reference_id == book.book_reference_id).scalar()
|
||||
if not count:
|
||||
@ -447,7 +454,7 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
||||
:param book_ref_id: The book reference id.
|
||||
:param chapter: The chapter to get the verse count for.
|
||||
"""
|
||||
log.debug('BibleDB.get_verse_count("%s", "%s")', book_ref_id, chapter)
|
||||
log.debug('BibleDB.get_verse_count("%s", "%s")' % (book_ref_id, chapter))
|
||||
count = self.session.query(func.max(Verse.verse)).join(Book) \
|
||||
.filter(Book.book_reference_id == book_ref_id) \
|
||||
.filter(Verse.chapter == chapter) \
|
||||
@ -563,7 +570,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
:param name: The name or abbreviation of the book.
|
||||
:param lower: True if the comparison should be only lowercase
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_book("%s")', name)
|
||||
log.debug('BiblesResourcesDB.get_book("%s")' % name)
|
||||
if not isinstance(name, str):
|
||||
name = str(name)
|
||||
if lower:
|
||||
@ -592,7 +599,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
|
||||
:param string: The string to search for in the book names or abbreviations.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_book_like("%s")', string)
|
||||
log.debug('BiblesResourcesDB.get_book_like("%s")' % string)
|
||||
if not isinstance(string, str):
|
||||
name = str(string)
|
||||
books = BiblesResourcesDB.run_sql(
|
||||
@ -611,17 +618,17 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_book_by_id(id):
|
||||
def get_book_by_id(book_id):
|
||||
"""
|
||||
Return a book by id.
|
||||
|
||||
:param id: The id of the book.
|
||||
:param book_id: The id of the book.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_book_by_id("%s")', id)
|
||||
if not isinstance(id, int):
|
||||
id = int(id)
|
||||
log.debug('BiblesResourcesDB.get_book_by_id("%s")' % book_id)
|
||||
if not isinstance(book_id, int):
|
||||
book_id = int(book_id)
|
||||
books = BiblesResourcesDB.run_sql(
|
||||
'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference WHERE id = ?', (id, ))
|
||||
'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference WHERE id = ?', (book_id, ))
|
||||
if books:
|
||||
return {
|
||||
'id': books[0][0],
|
||||
@ -641,7 +648,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
:param book_ref_id: The id of a book.
|
||||
:param chapter: The chapter number.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_chapter("%s", "%s")', book_ref_id, chapter)
|
||||
log.debug('BiblesResourcesDB.get_chapter("%s", "%s")' % (book_ref_id, chapter))
|
||||
if not isinstance(chapter, int):
|
||||
chapter = int(chapter)
|
||||
chapters = BiblesResourcesDB.run_sql(
|
||||
@ -649,10 +656,10 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
'chapter, verse_count FROM chapters WHERE book_reference_id = ?', (book_ref_id,))
|
||||
try:
|
||||
return {
|
||||
'id': chapters[chapter-1][0],
|
||||
'book_reference_id': chapters[chapter-1][1],
|
||||
'chapter': chapters[chapter-1][2],
|
||||
'verse_count': chapters[chapter-1][3]
|
||||
'id': chapters[chapter - 1][0],
|
||||
'book_reference_id': chapters[chapter - 1][1],
|
||||
'chapter': chapters[chapter - 1][2],
|
||||
'verse_count': chapters[chapter - 1][3]
|
||||
}
|
||||
except (IndexError, TypeError):
|
||||
return None
|
||||
@ -664,7 +671,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
|
||||
:param book_ref_id: The id of the book.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_chapter_count("%s")', book_ref_id)
|
||||
log.debug('BiblesResourcesDB.get_chapter_count("%s")' % book_ref_id)
|
||||
details = BiblesResourcesDB.get_book_by_id(book_ref_id)
|
||||
if details:
|
||||
return details['chapters']
|
||||
@ -678,7 +685,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
:param book_ref_id: The id of the book.
|
||||
:param chapter: The number of the chapter.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_verse_count("%s", "%s")', book_ref_id, chapter)
|
||||
log.debug('BiblesResourcesDB.get_verse_count("%s", "%s")' % (book_ref_id, chapter))
|
||||
details = BiblesResourcesDB.get_chapter(book_ref_id, chapter)
|
||||
if details:
|
||||
return details['verse_count']
|
||||
@ -691,7 +698,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
|
||||
:param source: The name or abbreviation of the book.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_download_source("%s")', source)
|
||||
log.debug('BiblesResourcesDB.get_download_source("%s")' % source)
|
||||
if not isinstance(source, str):
|
||||
source = str(source)
|
||||
source = source.title()
|
||||
@ -712,7 +719,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
|
||||
:param source: The source of the web_bible.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_webbibles("%s")', source)
|
||||
log.debug('BiblesResourcesDB.get_webbibles("%s")' % source)
|
||||
if not isinstance(source, str):
|
||||
source = str(source)
|
||||
source = BiblesResourcesDB.get_download_source(source)
|
||||
@ -737,7 +744,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
:param abbreviation: The abbreviation of the web_bible.
|
||||
:param source: The source of the web_bible.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_webbibles("%s", "%s")', abbreviation, source)
|
||||
log.debug('BiblesResourcesDB.get_webbibles("%s", "%s")' % (abbreviation, source))
|
||||
if not isinstance(abbreviation, str):
|
||||
abbreviation = str(abbreviation)
|
||||
if not isinstance(source, str):
|
||||
@ -765,7 +772,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
:param name: The name to search the id.
|
||||
:param language_id: The language_id for which language should be searched
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_alternative_book_name("%s", "%s")', name, language_id)
|
||||
log.debug('BiblesResourcesDB.get_alternative_book_name("%s", "%s")' % (name, language_id))
|
||||
if language_id:
|
||||
books = BiblesResourcesDB.run_sql(
|
||||
'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ? ORDER BY id',
|
||||
@ -784,7 +791,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
|
||||
|
||||
:param name: The name or abbreviation of the language.
|
||||
"""
|
||||
log.debug('BiblesResourcesDB.get_language("%s")', name)
|
||||
log.debug('BiblesResourcesDB.get_language("%s")' % name)
|
||||
if not isinstance(name, str):
|
||||
name = str(name)
|
||||
language = BiblesResourcesDB.run_sql(
|
||||
@ -846,13 +853,13 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
|
||||
file_path = os.path.join(
|
||||
AppLocation.get_directory(AppLocation.DataDir), 'bibles', 'alternative_book_names.sqlite')
|
||||
if not os.path.exists(file_path):
|
||||
#create new DB, create table alternative_book_names
|
||||
# create new DB, create table alternative_book_names
|
||||
AlternativeBookNamesDB.conn = sqlite3.connect(file_path)
|
||||
AlternativeBookNamesDB.conn.execute(
|
||||
'CREATE TABLE alternative_book_names(id INTEGER NOT NULL, '
|
||||
'book_reference_id INTEGER, language_id INTEGER, name VARCHAR(50), PRIMARY KEY (id))')
|
||||
else:
|
||||
#use existing DB
|
||||
# use existing DB
|
||||
AlternativeBookNamesDB.conn = sqlite3.connect(file_path)
|
||||
AlternativeBookNamesDB.cursor = AlternativeBookNamesDB.conn.cursor()
|
||||
return AlternativeBookNamesDB.cursor
|
||||
@ -880,7 +887,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
|
||||
:param name: The name to search the id.
|
||||
:param language_id: The language_id for which language should be searched
|
||||
"""
|
||||
log.debug('AlternativeBookNamesDB.get_book_reference_id("%s", "%s")', name, language_id)
|
||||
log.debug('AlternativeBookNamesDB.get_book_reference_id("%s", "%s")' % (name, language_id))
|
||||
if language_id:
|
||||
books = AlternativeBookNamesDB.run_sql(
|
||||
'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ?', (language_id, ))
|
||||
@ -901,8 +908,8 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
|
||||
:param book_reference_id: The book_reference_id of the book.
|
||||
:param language_id: The language to which the alternative book name belong.
|
||||
"""
|
||||
log.debug('AlternativeBookNamesDB.create_alternative_book_name("%s", "%s", "%s")',
|
||||
name, book_reference_id, language_id)
|
||||
log.debug('AlternativeBookNamesDB.create_alternative_book_name("%s", "%s", "%s")' %
|
||||
(name, book_reference_id, language_id))
|
||||
return AlternativeBookNamesDB.run_sql(
|
||||
'INSERT INTO alternative_book_names(book_reference_id, language_id, name) '
|
||||
'VALUES (?, ?, ?)', (book_reference_id, language_id, name), True)
|
||||
|
@ -552,10 +552,10 @@ class HTTPBible(BibleDB, RegistryProperties):
|
||||
self.application.set_busy_cursor()
|
||||
search_results = self.get_chapter(book, reference[1])
|
||||
if search_results and search_results.has_verse_list():
|
||||
## We have found a book of the bible lets check to see
|
||||
## if it was there. By reusing the returned book name
|
||||
## we get a correct book. For example it is possible
|
||||
## to request ac and get Acts back.
|
||||
# We have found a book of the bible lets check to see
|
||||
# if it was there. By reusing the returned book name
|
||||
# we get a correct book. For example it is possible
|
||||
# to request ac and get Acts back.
|
||||
book_name = search_results.book
|
||||
self.application.process_events()
|
||||
# Check to see if book/chapter exists.
|
||||
|
@ -480,6 +480,10 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.reload_bibles()
|
||||
|
||||
def on_delete_click(self):
|
||||
"""
|
||||
When the delete button is pressed
|
||||
"""
|
||||
bible = None
|
||||
if self.quickTab.isVisible():
|
||||
bible = self.quickVersionComboBox.currentText()
|
||||
elif self.advancedTab.isVisible():
|
||||
@ -488,8 +492,9 @@ class BibleMediaItem(MediaManagerItem):
|
||||
if QtGui.QMessageBox.question(
|
||||
self, UiStrings().ConfirmDelete,
|
||||
translate('BiblesPlugin.MediaItem', 'Are you sure you want to completely delete "%s" Bible from '
|
||||
'OpenLP?\n\nYou will need to re-import this Bible to use it again.') % bible,
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
||||
'OpenLP?\n\nYou will need to re-import this Bible to use it '
|
||||
'again.') % bible,
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
||||
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
|
||||
return
|
||||
self.plugin.manager.delete_bible(bible)
|
||||
@ -752,7 +757,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
log.exception('The second_search_results does not have as many verses as the search_results.')
|
||||
break
|
||||
bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version,
|
||||
second_version)
|
||||
second_version)
|
||||
else:
|
||||
bible_text = '%s %d%s%d (%s)' % (book, verse.chapter, verse_separator, verse.verse, version)
|
||||
bible_verse = QtGui.QListWidgetItem(bible_text)
|
||||
@ -840,6 +845,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanWordSplit)
|
||||
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
||||
# Service Item: Title
|
||||
service_item.title = create_separated_list(raw_title)
|
||||
# Service Item: Theme
|
||||
|
@ -94,5 +94,5 @@ class VerseReferenceList(object):
|
||||
result = result + ', ' + version['permission']
|
||||
result = result.rstrip()
|
||||
if result.endswith(','):
|
||||
return result[:len(result)-1]
|
||||
return result[:len(result) - 1]
|
||||
return result
|
||||
|
@ -43,7 +43,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
__default_settings__ = {
|
||||
'custom/db type': 'sqlite',
|
||||
'custom/last search type': CustomSearch.Titles,
|
||||
'custom/last search type': CustomSearch.Titles,
|
||||
'custom/display footer': True,
|
||||
'custom/add custom from service': True
|
||||
}
|
||||
@ -97,12 +97,12 @@ class CustomPlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('CustomPlugin', 'Custom Slide', 'name singular'),
|
||||
'plural': translate('CustomPlugin', 'Custom Slides', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('CustomPlugin', 'Custom Slides', 'container title')
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
#lint:disable
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
|
@ -51,7 +51,7 @@ from lxml import etree, objectify
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
#TODO: These classes need to be refactored into a single class.
|
||||
# TODO: These classes need to be refactored into a single class.
|
||||
class CustomXMLBuilder(object):
|
||||
"""
|
||||
This class builds the XML used to describe songs.
|
||||
|
@ -95,12 +95,12 @@ class ImagePlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin.
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('ImagePlugin', 'Image', 'name singular'),
|
||||
'plural': translate('ImagePlugin', 'Images', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {'title': translate('ImagePlugin', 'Images', 'container title')}
|
||||
# Middle Header Bar
|
||||
tooltips = {
|
||||
|
@ -550,6 +550,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanAppend)
|
||||
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
||||
# force a nonexistent theme
|
||||
service_item.theme = -1
|
||||
missing_items_file_names = []
|
||||
|
@ -95,7 +95,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
||||
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
||||
self.automatic = UiStrings().Automatic
|
||||
self.display_type_label.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
||||
#self.rebuild_players()
|
||||
|
||||
def required_icons(self):
|
||||
"""
|
||||
@ -141,7 +140,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
||||
if index == 0:
|
||||
set_media_players(player)
|
||||
else:
|
||||
set_media_players(player, player[index-1])
|
||||
set_media_players(player, player[index - 1])
|
||||
|
||||
def on_reset_click(self):
|
||||
"""
|
||||
@ -216,6 +215,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
||||
if not self.media_controller.media_length(service_item):
|
||||
return False
|
||||
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
||||
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||
if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked:
|
||||
service_item.will_auto_start = True
|
||||
|
@ -73,12 +73,12 @@ class MediaPlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('MediaPlugin', 'Media', 'name singular'),
|
||||
'plural': translate('MediaPlugin', 'Media', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('MediaPlugin', 'Media', 'container title')
|
||||
}
|
||||
|
@ -377,8 +377,6 @@ class ImpressDocument(PresentationDocument):
|
||||
Stop the presentation, remove from screen.
|
||||
"""
|
||||
log.debug('stop presentation OpenOffice')
|
||||
# deactivate should hide the screen according to docs, but doesn't
|
||||
#self.control.deactivate()
|
||||
self.presentation.end()
|
||||
self.control = None
|
||||
|
||||
|
@ -263,6 +263,7 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
file_type = os.path.splitext(filename)[1][1:]
|
||||
if not self.display_type_combo_box.currentText():
|
||||
return False
|
||||
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
||||
if (file_type == 'pdf' or file_type == 'xps') and context != ServiceItemContext.Service:
|
||||
service_item.add_capability(ItemCapabilities.CanMaintain)
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
|
@ -74,7 +74,7 @@ class PdfController(PresentationController):
|
||||
runlog = ''
|
||||
log.debug('testing program_path: %s', program_path)
|
||||
try:
|
||||
runlog = check_output([program_path, '--help'], stderr=STDOUT)
|
||||
runlog = check_output([program_path, '--help'], stderr=STDOUT)
|
||||
except CalledProcessError as e:
|
||||
runlog = e.output
|
||||
except Exception:
|
||||
@ -183,7 +183,7 @@ class PdfDocument(PresentationDocument):
|
||||
self.image_files = []
|
||||
self.num_pages = -1
|
||||
|
||||
def gs_get_resolution(self, size):
|
||||
def gs_get_resolution(self, size):
|
||||
"""
|
||||
Only used when using ghostscript
|
||||
Ghostscript can't scale automatically while keeping aspect like mupdf, so we need
|
||||
@ -204,19 +204,19 @@ class PdfDocument(PresentationDocument):
|
||||
log.debug(' '.join(e.cmd))
|
||||
log.debug(e.output)
|
||||
# Extract the pdf resolution from output, the format is " Size: x: <width>, y: <height>"
|
||||
width = 0
|
||||
height = 0
|
||||
width = 0.0
|
||||
height = 0.0
|
||||
for line in runlog.splitlines():
|
||||
try:
|
||||
width = int(re.search('.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1))
|
||||
height = int(re.search('.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1))
|
||||
width = float(re.search('.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1))
|
||||
height = float(re.search('.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1))
|
||||
break
|
||||
except AttributeError:
|
||||
pass
|
||||
continue
|
||||
# Calculate the ratio from pdf to screen
|
||||
if width > 0 and height > 0:
|
||||
width_ratio = size.right() / float(width)
|
||||
height_ratio = size.bottom() / float(height)
|
||||
width_ratio = size.right() / width
|
||||
height_ratio = size.bottom() / height
|
||||
# return the resolution that should be used. 72 is default.
|
||||
if width_ratio > height_ratio:
|
||||
return int(height_ratio * 72)
|
||||
@ -236,7 +236,7 @@ class PdfDocument(PresentationDocument):
|
||||
if os.path.isfile(os.path.join(self.get_temp_folder(), 'mainslide001.png')):
|
||||
created_files = sorted(os.listdir(self.get_temp_folder()))
|
||||
for fn in created_files:
|
||||
if os.path.isfile(os.path.join(self.get_temp_folder(), fn)):
|
||||
if os.path.isfile(os.path.join(self.get_temp_folder(), fn)):
|
||||
self.image_files.append(os.path.join(self.get_temp_folder(), fn))
|
||||
self.num_pages = len(self.image_files)
|
||||
return True
|
||||
|
@ -247,7 +247,7 @@ class PowerpointDocument(PresentationDocument):
|
||||
Starts a presentation from the beginning.
|
||||
"""
|
||||
log.debug('start_presentation')
|
||||
#SlideShowWindow measures its size/position by points, not pixels
|
||||
# SlideShowWindow measures its size/position by points, not pixels
|
||||
try:
|
||||
dpi = win32ui.GetActiveWindow().GetDC().GetDeviceCaps(88)
|
||||
except win32ui.error:
|
||||
|
@ -122,8 +122,10 @@ class PresentationDocument(object):
|
||||
a file, e.g. thumbnails
|
||||
"""
|
||||
try:
|
||||
shutil.rmtree(self.get_thumbnail_folder())
|
||||
shutil.rmtree(self.get_temp_folder())
|
||||
if os.path.exists(self.get_thumbnail_folder()):
|
||||
shutil.rmtree(self.get_thumbnail_folder())
|
||||
if os.path.exists(self.get_temp_folder()):
|
||||
shutil.rmtree(self.get_temp_folder())
|
||||
except OSError:
|
||||
log.exception('Failed to delete presentation controller files')
|
||||
|
||||
|
@ -175,10 +175,10 @@ class PresentationTab(SettingsTab):
|
||||
if pdf_program == '':
|
||||
enable_pdf_program = 0
|
||||
if pdf_program != Settings().value(self.settings_section + '/pdf_program'):
|
||||
Settings().setValue(self.settings_section + '/pdf_program', pdf_program)
|
||||
Settings().setValue(self.settings_section + '/pdf_program', pdf_program)
|
||||
changed = True
|
||||
if enable_pdf_program != Settings().value(self.settings_section + '/enable_pdf_program'):
|
||||
Settings().setValue(self.settings_section + '/enable_pdf_program', enable_pdf_program)
|
||||
Settings().setValue(self.settings_section + '/enable_pdf_program', enable_pdf_program)
|
||||
changed = True
|
||||
if changed:
|
||||
self.settings_form.register_post_process('mediaitem_suffix_reset')
|
||||
|
@ -156,12 +156,12 @@ class PresentationPlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin.
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('PresentationPlugin', 'Presentation', 'name singular'),
|
||||
'plural': translate('PresentationPlugin', 'Presentations', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('PresentationPlugin', 'Presentations', 'container title')
|
||||
}
|
||||
|
@ -92,12 +92,12 @@ class RemotesPlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('RemotePlugin', 'Remote', 'name singular'),
|
||||
'plural': translate('RemotePlugin', 'Remotes', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('RemotePlugin', 'Remote', 'container title')
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ The duplicate song removal logic for OpenLP.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
@ -45,6 +46,18 @@ from openlp.plugins.songs.lib.songcompare import songs_probably_equal
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def song_generator(songs):
|
||||
"""
|
||||
This is a generator function to return tuples of two songs. When completed then all songs have once been returned
|
||||
combined with any other songs.
|
||||
|
||||
:param songs: All songs in the database.
|
||||
"""
|
||||
for outer_song_counter in range(len(songs) - 1):
|
||||
for inner_song_counter in range(outer_song_counter + 1, len(songs)):
|
||||
yield (songs[outer_song_counter], songs[inner_song_counter])
|
||||
|
||||
|
||||
class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
|
||||
"""
|
||||
This is the Duplicate Song Removal Wizard. It provides functionality to search for and remove duplicate songs
|
||||
@ -114,7 +127,7 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
|
||||
self.review_layout.addWidget(self.review_scroll_area)
|
||||
self.review_page_id = self.addPage(self.review_page)
|
||||
# Add a dummy page to the end, to prevent the finish button to appear and the next button do disappear on the
|
||||
#review page.
|
||||
# review page.
|
||||
self.dummy_page = QtGui.QWizardPage()
|
||||
self.dummy_page_id = self.addPage(self.dummy_page)
|
||||
|
||||
@ -167,24 +180,31 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
|
||||
max_progress_count = max_songs * (max_songs - 1) // 2
|
||||
self.duplicate_search_progress_bar.setMaximum(max_progress_count)
|
||||
songs = self.plugin.manager.get_all_objects(Song)
|
||||
for outer_song_counter in range(max_songs - 1):
|
||||
for inner_song_counter in range(outer_song_counter + 1, max_songs):
|
||||
if songs_probably_equal(songs[outer_song_counter], songs[inner_song_counter]):
|
||||
duplicate_added = self.add_duplicates_to_song_list(
|
||||
songs[outer_song_counter], songs[inner_song_counter])
|
||||
if duplicate_added:
|
||||
self.found_duplicates_edit.appendPlainText(
|
||||
songs[outer_song_counter].title + " = " + songs[inner_song_counter].title)
|
||||
self.duplicate_search_progress_bar.setValue(self.duplicate_search_progress_bar.value() + 1)
|
||||
# The call to process_events() will keep the GUI responsive.
|
||||
self.application.process_events()
|
||||
if self.break_search:
|
||||
return
|
||||
# Create a worker/process pool to check the songs.
|
||||
process_number = max(1, multiprocessing.cpu_count() - 1)
|
||||
pool = multiprocessing.Pool(process_number)
|
||||
result = pool.imap_unordered(songs_probably_equal, song_generator(songs), 30)
|
||||
# Do not accept any further tasks. Also this closes the processes if all tasks are done.
|
||||
pool.close()
|
||||
# While the processes are still working, start to look at the results.
|
||||
for song_tuple in result:
|
||||
self.duplicate_search_progress_bar.setValue(self.duplicate_search_progress_bar.value() + 1)
|
||||
# The call to process_events() will keep the GUI responsive.
|
||||
self.application.process_events()
|
||||
if self.break_search:
|
||||
pool.terminate()
|
||||
return
|
||||
if song_tuple is None:
|
||||
continue
|
||||
song1, song2 = song_tuple
|
||||
duplicate_added = self.add_duplicates_to_song_list(song1, song2)
|
||||
if duplicate_added:
|
||||
self.found_duplicates_edit.appendPlainText(song1.title + " = " + song2.title)
|
||||
self.review_total_count = len(self.duplicate_song_list)
|
||||
if self.review_total_count == 0:
|
||||
self.notify_no_duplicates()
|
||||
else:
|
||||
if self.duplicate_song_list:
|
||||
self.button(QtGui.QWizard.NextButton).show()
|
||||
else:
|
||||
self.notify_no_duplicates()
|
||||
finally:
|
||||
self.application.set_normal_cursor()
|
||||
elif page_id == self.review_page_id:
|
||||
@ -217,12 +237,12 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
|
||||
duplicate_added = False
|
||||
for duplicate_group in self.duplicate_song_list:
|
||||
# Skip the first song in the duplicate lists, since the first one has to be an earlier song.
|
||||
if search_song in duplicate_group and not duplicate_song in duplicate_group:
|
||||
if search_song in duplicate_group and duplicate_song not in duplicate_group:
|
||||
duplicate_group.append(duplicate_song)
|
||||
duplicate_group_found = True
|
||||
duplicate_added = True
|
||||
break
|
||||
elif not search_song in duplicate_group and duplicate_song in duplicate_group:
|
||||
elif search_song not in duplicate_group and duplicate_song in duplicate_group:
|
||||
duplicate_group.append(search_song)
|
||||
duplicate_group_found = True
|
||||
duplicate_added = True
|
||||
|
@ -675,14 +675,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
separator = parts.find(':')
|
||||
if separator >= 0:
|
||||
verse_name = parts[0:separator].strip()
|
||||
verse_num = parts[separator+1:].strip()
|
||||
verse_num = parts[separator + 1:].strip()
|
||||
else:
|
||||
verse_name = parts
|
||||
verse_num = '1'
|
||||
verse_index = VerseType.from_loose_input(verse_name)
|
||||
verse_tag = VerseType.tags[verse_index]
|
||||
# Later we need to handle v1a as well.
|
||||
#regex = re.compile(r'(\d+\w.)')
|
||||
regex = re.compile(r'\D*(\d+)\D*')
|
||||
match = regex.match(verse_num)
|
||||
if match:
|
||||
|
@ -75,7 +75,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
||||
text = self.verse_text_edit.toPlainText()
|
||||
position = self.verse_text_edit.textCursor().position()
|
||||
insert_string = '[---]'
|
||||
if position and text[position-1] != '\n':
|
||||
if position and text[position - 1] != '\n':
|
||||
insert_string = '\n' + insert_string
|
||||
if position == len(text) or text[position] != '\n':
|
||||
insert_string += '\n'
|
||||
|
@ -66,8 +66,10 @@ class Ui_MediaFilesDialog(object):
|
||||
def retranslateUi(self, media_files_dialog):
|
||||
"""
|
||||
Translate the UI on the fly.
|
||||
|
||||
:param media_files_dialog:
|
||||
"""
|
||||
media_files_dialog.setWindowTitle(translate('SongsPlugin.MediaFilesForm', 'Select Media File(s)'))
|
||||
self.select_label.setText(translate('SongsPlugin.MediaFilesForm',
|
||||
'Select one or more audio files from the list below, and click OK to import them '
|
||||
'into this song.'))
|
||||
self.select_label.setText(translate('SongsPlugin.MediaFilesForm', 'Select one or more audio files from the '
|
||||
'list below, and click OK to import them '
|
||||
'into this song.'))
|
||||
|
@ -152,9 +152,9 @@ class SongExportForm(OpenLPWizard):
|
||||
self.setWindowTitle(translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard'))
|
||||
self.title_label.setText(WizardStrings.HeaderStyle %
|
||||
translate('OpenLP.Ui', 'Welcome to the Song Export Wizard'))
|
||||
self.information_label.setText(translate('SongsPlugin.ExportWizardForm', 'This wizard will help to'
|
||||
' export your songs to the open and free <strong>OpenLyrics </strong> worship '
|
||||
'song format.'))
|
||||
self.information_label.setText(
|
||||
translate('SongsPlugin.ExportWizardForm', 'This wizard will help to export your songs to the open and free '
|
||||
'<strong>OpenLyrics </strong> worship song format.'))
|
||||
self.available_songs_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Songs'))
|
||||
self.available_songs_page.setSubTitle(translate('SongsPlugin.ExportWizardForm',
|
||||
'Check the songs you want to export.'))
|
||||
|
@ -270,13 +270,13 @@ class CCLIFileImport(SongImport):
|
||||
verse_text = ''
|
||||
verse_start = False
|
||||
else:
|
||||
#line_number=0, song title
|
||||
# line_number=0, song title
|
||||
if line_number == 0:
|
||||
self.title = clean_line
|
||||
line_number += 1
|
||||
#line_number=1, verses
|
||||
# line_number=1, verses
|
||||
elif line_number == 1:
|
||||
#line_number=1, ccli number, first line after verses
|
||||
# line_number=1, ccli number, first line after verses
|
||||
if clean_line.startswith('CCLI'):
|
||||
line_number += 1
|
||||
ccli_parts = clean_line.split(' ')
|
||||
@ -319,21 +319,21 @@ class CCLIFileImport(SongImport):
|
||||
# last part. Add l so as to keep the CRLF
|
||||
verse_text = verse_text + line
|
||||
else:
|
||||
#line_number=2, copyright
|
||||
# line_number=2, copyright
|
||||
if line_number == 2:
|
||||
line_number += 1
|
||||
if clean_line.startswith('©'):
|
||||
self.copyright = clean_line
|
||||
else:
|
||||
song_author = clean_line
|
||||
#n=3, authors
|
||||
# n=3, authors
|
||||
elif line_number == 3:
|
||||
line_number += 1
|
||||
if song_author:
|
||||
self.copyright = clean_line
|
||||
else:
|
||||
song_author = clean_line
|
||||
#line_number=4, comments lines before last line
|
||||
# line_number=4, comments lines before last line
|
||||
elif line_number == 4 and not clean_line.startswith('CCL'):
|
||||
self.comments += clean_line
|
||||
# split on known separators
|
||||
|
@ -437,7 +437,7 @@ class EasyWorshipSongImport(SongImport):
|
||||
elif field_desc.field_type == FieldType.Logical:
|
||||
return field ^ 0x80 == 1
|
||||
elif field_desc.field_type == FieldType.Memo or field_desc.field_type == FieldType.Blob:
|
||||
block_start, blob_size = struct.unpack_from('<II', field, len(field)-10)
|
||||
block_start, blob_size = struct.unpack_from('<II', field, len(field) - 10)
|
||||
sub_block = block_start & 0xff
|
||||
block_start &= ~0xff
|
||||
self.memo_file.seek(block_start)
|
||||
|
@ -96,7 +96,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
|
||||
def add_end_header_bar(self):
|
||||
self.toolbar.addSeparator()
|
||||
## Song Maintenance Button ##
|
||||
# Song Maintenance Button
|
||||
self.maintenance_action = self.toolbar.add_toolbar_action('maintenance_action',
|
||||
icon=':/songs/song_maintenance.png',
|
||||
triggers=self.on_song_maintenance_click)
|
||||
@ -266,7 +266,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
# Do not display temporary songs
|
||||
if song.temporary:
|
||||
continue
|
||||
if song_number and not song_number in song.song_number:
|
||||
if song_number and song_number not in song.song_number:
|
||||
continue
|
||||
song_detail = '%s - %s (%s)' % (book.name, song.song_number, song.title)
|
||||
song_name = QtGui.QListWidgetItem(song_detail)
|
||||
|
@ -56,11 +56,15 @@ class SongBeamerTypes(object):
|
||||
'Zwischenspiel': VerseType.tags[VerseType.Bridge],
|
||||
'Pre-Chorus': VerseType.tags[VerseType.PreChorus],
|
||||
'Pre-Refrain': VerseType.tags[VerseType.PreChorus],
|
||||
'Misc': VerseType.tags[VerseType.Other],
|
||||
'Pre-Bridge': VerseType.tags[VerseType.Other],
|
||||
'Pre-Coda': VerseType.tags[VerseType.Other],
|
||||
'Part': VerseType.tags[VerseType.Other],
|
||||
'Teil': VerseType.tags[VerseType.Other],
|
||||
'Unbekannt': VerseType.tags[VerseType.Other],
|
||||
'Unknown': VerseType.tags[VerseType.Other],
|
||||
'Unbenannt': VerseType.tags[VerseType.Other]
|
||||
'Unbenannt': VerseType.tags[VerseType.Other],
|
||||
'$$M=': VerseType.tags[VerseType.Other]
|
||||
}
|
||||
|
||||
|
||||
@ -132,7 +136,8 @@ class SongBeamerImport(SongImport):
|
||||
line = str(line).strip()
|
||||
if line.startswith('#') and not read_verses:
|
||||
self.parseTags(line)
|
||||
elif line.startswith('---'):
|
||||
elif line.startswith('--'):
|
||||
# --- and -- allowed for page-breaks (difference in Songbeamer only in printout)
|
||||
if self.current_verse:
|
||||
self.replace_html_tags()
|
||||
self.add_verse(self.current_verse, self.current_verse_type)
|
||||
@ -282,4 +287,7 @@ class SongBeamerImport(SongImport):
|
||||
if marks[1].isdigit():
|
||||
self.current_verse_type += marks[1]
|
||||
return True
|
||||
elif marks[0].startswith('$$M='): # this verse-mark cannot be numbered
|
||||
self.current_verse_type = SongBeamerTypes.MarkTypes['$$M=']
|
||||
return True
|
||||
return False
|
||||
|
@ -52,13 +52,13 @@ MIN_BLOCK_SIZE = 70
|
||||
MAX_TYPO_SIZE = 3
|
||||
|
||||
|
||||
def songs_probably_equal(song1, song2):
|
||||
def songs_probably_equal(song_tupel):
|
||||
"""
|
||||
Calculate and return whether two songs are probably equal.
|
||||
|
||||
:param song1: The first song to compare.
|
||||
:param song2: The second song to compare.
|
||||
:param song_tupel: A tuple of two songs to compare.
|
||||
"""
|
||||
song1, song2 = song_tupel
|
||||
if len(song1.search_lyrics) < len(song2.search_lyrics):
|
||||
small = song1.search_lyrics
|
||||
large = song2.search_lyrics
|
||||
@ -75,18 +75,19 @@ def songs_probably_equal(song1, song2):
|
||||
for element in diff_no_typos:
|
||||
if element[0] == "equal" and _op_length(element) >= MIN_BLOCK_SIZE:
|
||||
length_of_equal_blocks += _op_length(element)
|
||||
|
||||
if length_of_equal_blocks >= MIN_BLOCK_SIZE:
|
||||
return True
|
||||
return song1, song2
|
||||
# Check 2: Similarity based on the relative length of the longest equal block.
|
||||
# Calculate the length of the largest equal block of the diff set.
|
||||
length_of_longest_equal_block = 0
|
||||
for element in diff_no_typos:
|
||||
if element[0] == "equal" and _op_length(element) > length_of_longest_equal_block:
|
||||
length_of_longest_equal_block = _op_length(element)
|
||||
if length_of_equal_blocks >= MIN_BLOCK_SIZE or length_of_longest_equal_block > len(small) * 2 // 3:
|
||||
return True
|
||||
if length_of_longest_equal_block > len(small) * 2 // 3:
|
||||
return song1, song2
|
||||
# Both checks failed. We assume the songs are not equal.
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def _op_length(opcode):
|
||||
|
@ -675,6 +675,7 @@ class OpenLyrics(object):
|
||||
sxml = SongXML()
|
||||
verses = {}
|
||||
verse_def_list = []
|
||||
verse_order = self._text(properties.verseOrder).split(' ') if hasattr(properties, 'verseOrder') else []
|
||||
try:
|
||||
lyrics = song_xml.lyrics
|
||||
except AttributeError:
|
||||
@ -717,13 +718,17 @@ class OpenLyrics(object):
|
||||
else:
|
||||
verses[(verse_tag, verse_number, lang, translit, verse_part)] = text
|
||||
verse_def_list.append((verse_tag, verse_number, lang, translit, verse_part))
|
||||
# Update verse order when the verse name has changed
|
||||
if verse_def != verse_tag + verse_number + verse_part:
|
||||
for i in range(len(verse_order)):
|
||||
if verse_order[i] == verse_def:
|
||||
verse_order[i] = verse_tag + verse_number + verse_part
|
||||
# We have to use a list to keep the order, as dicts are not sorted.
|
||||
for verse in verse_def_list:
|
||||
sxml.add_verse_to_lyrics(verse[0], verse[1], verses[verse], verse[2])
|
||||
song_obj.lyrics = str(sxml.extract_xml(), 'utf-8')
|
||||
# Process verse order
|
||||
if hasattr(properties, 'verseOrder'):
|
||||
song_obj.verse_order = self._text(properties.verseOrder)
|
||||
song_obj.verse_order = ' '.join(verse_order)
|
||||
|
||||
def _process_songbooks(self, properties, song):
|
||||
"""
|
||||
|
@ -132,7 +132,7 @@ class SongsPlugin(Plugin):
|
||||
)
|
||||
import_menu.addAction(self.import_songselect_item)
|
||||
|
||||
def add_export_menu_Item(self, export_menu):
|
||||
def add_export_menu_item(self, export_menu):
|
||||
"""
|
||||
Give the Songs plugin the opportunity to add items to the **Export** menu.
|
||||
|
||||
@ -261,12 +261,12 @@ class SongsPlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('SongsPlugin', 'Song', 'name singular'),
|
||||
'plural': translate('SongsPlugin', 'Songs', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('SongsPlugin', 'Songs', 'container title')
|
||||
}
|
||||
|
@ -246,12 +246,12 @@ class SongUsagePlugin(Plugin):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Name PluginList ##
|
||||
# Name PluginList
|
||||
self.text_strings[StringContent.Name] = {
|
||||
'singular': translate('SongUsagePlugin', 'SongUsage', 'name singular'),
|
||||
'plural': translate('SongUsagePlugin', 'SongUsage', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
# Name for MediaDockManager, SettingsManager
|
||||
self.text_strings[StringContent.VisibleName] = {
|
||||
'title': translate('SongUsagePlugin', 'SongUsage', 'container title')
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ You can look up the token in the Branch-01-Pull job configuration or ask in IRC.
|
||||
"""
|
||||
|
||||
from optparse import OptionParser
|
||||
import re
|
||||
from requests.exceptions import HTTPError
|
||||
from subprocess import Popen, PIPE
|
||||
import sys
|
||||
@ -49,6 +50,9 @@ from jenkins import Jenkins
|
||||
|
||||
|
||||
JENKINS_URL = 'http://ci.openlp.org/'
|
||||
REPO_REGEX = r'(.*/+)(~.*)'
|
||||
# Allows us to black list token. So when we change the token, we can display a proper message to the user.
|
||||
OLD_TOKENS = []
|
||||
|
||||
|
||||
class OpenLPJobs(object):
|
||||
@ -59,9 +63,20 @@ class OpenLPJobs(object):
|
||||
Branch_Functional = 'Branch-02-Functional-Tests'
|
||||
Branch_Interface = 'Branch-03-Interface-Tests'
|
||||
Branch_Windows = 'Branch-04-Windows_Tests'
|
||||
Branch_PEP = 'Branch-05-Code-Analysis'
|
||||
Branch_PEP = 'Branch-05a-Code_Analysis'
|
||||
Branch_Coverage = 'Branch-05b-Test_Coverage'
|
||||
|
||||
Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP]
|
||||
Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP, Branch_Coverage]
|
||||
|
||||
|
||||
class Colour(object):
|
||||
"""
|
||||
This class holds values which can be used to print coloured text.
|
||||
"""
|
||||
RED_START = '\033[1;31m'
|
||||
RED_END = '\033[1;m'
|
||||
GREEN_START = '\033[1;32m'
|
||||
GREEN_END = '\033[1;m'
|
||||
|
||||
|
||||
class JenkinsTrigger(object):
|
||||
@ -79,14 +94,25 @@ class JenkinsTrigger(object):
|
||||
"""
|
||||
Ask our jenkins server to build the "Branch-01-Pull" job.
|
||||
"""
|
||||
self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name}, token=self.token)
|
||||
bzr = Popen(('bzr', 'whoami'), stdout=PIPE, stderr=PIPE)
|
||||
raw_output, error = bzr.communicate()
|
||||
# We just want the name (not the email).
|
||||
name = ' '.join(raw_output.decode().split()[:-1])
|
||||
cause = 'Build triggered by %s (%s)' % (name, self.repo_name)
|
||||
self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build(
|
||||
{'BRANCH_NAME': self.repo_name, 'cause': cause}, token=self.token)
|
||||
|
||||
def print_output(self):
|
||||
"""
|
||||
Print the status information of the build tirggered.
|
||||
"""
|
||||
print("Add this to your merge proposal:")
|
||||
print("--------------------------------")
|
||||
print('Add this to your merge proposal:')
|
||||
print('--------------------------------')
|
||||
bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE)
|
||||
raw_output, error = bzr.communicate()
|
||||
revno = raw_output.decode().strip()
|
||||
print('%s (revision %s)' % (get_repo_name(), revno))
|
||||
|
||||
for job in OpenLPJobs.Jobs:
|
||||
self.__print_build_info(job)
|
||||
|
||||
@ -107,17 +133,17 @@ class JenkinsTrigger(object):
|
||||
"""
|
||||
job = self.jenkins_instance.job(job_name)
|
||||
while job.info['inQueue']:
|
||||
# Give other processes the possibility to take over. Like Thread.yield().
|
||||
time.sleep(0)
|
||||
time.sleep(1)
|
||||
build = job.last_build
|
||||
build.wait()
|
||||
result_string = build.info['result']
|
||||
if build.info['result'] == 'SUCCESS':
|
||||
# Make 'SUCCESS' green.
|
||||
result_string = '%s%s%s' % (Colour.GREEN_START, build.info['result'], Colour.GREEN_END)
|
||||
else:
|
||||
# Make 'FAILURE' red.
|
||||
result_string = '%s%s%s' % (Colour.RED_START, build.info['result'], Colour.RED_END)
|
||||
url = build.info['url']
|
||||
print('[%s] %s' % (result_string, url))
|
||||
# On failure open the browser.
|
||||
#if result_string == "FAILURE":
|
||||
# url += 'console'
|
||||
# Popen(('xdg-open', url), stderr=PIPE)
|
||||
|
||||
|
||||
def get_repo_name():
|
||||
@ -139,46 +165,41 @@ def get_repo_name():
|
||||
for line in output_list:
|
||||
# Check if it is remote branch.
|
||||
if 'push branch' in line:
|
||||
repo_name = line.replace('push branch: bzr+ssh://bazaar.launchpad.net/', 'lp:')
|
||||
break
|
||||
match = re.match(REPO_REGEX, line)
|
||||
if match:
|
||||
repo_name = 'lp:%s' % match.group(2)
|
||||
break
|
||||
elif 'checkout of branch' in line:
|
||||
repo_name = line.replace('checkout of branch: bzr+ssh://bazaar.launchpad.net/', 'lp:')
|
||||
break
|
||||
repo_name = repo_name.strip('/')
|
||||
|
||||
# Did we find the branch name?
|
||||
if not repo_name:
|
||||
for line in output_list:
|
||||
# Check if the branch was pushed.
|
||||
if 'Shared repository with trees (format: 2a)' in line:
|
||||
print('Not a branch. cd to a branch.')
|
||||
return
|
||||
print('Not a branch. Have you pushed it to launchpad?')
|
||||
return
|
||||
return repo_name
|
||||
match = re.match(REPO_REGEX, line)
|
||||
if match:
|
||||
repo_name = 'lp:%s' % match.group(2)
|
||||
break
|
||||
return repo_name.strip('/')
|
||||
|
||||
|
||||
def main():
|
||||
usage = 'Usage: python %prog TOKEN [options]'
|
||||
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option('-d', '--disable-output', dest='enable_output', action="store_false", default=True,
|
||||
parser.add_option('-d', '--disable-output', dest='enable_output', action='store_false', default=True,
|
||||
help='Disable output.')
|
||||
parser.add_option('-b', '--open-browser', dest='open_browser', action="store_true", default=False,
|
||||
parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False,
|
||||
help='Opens the jenkins page in your browser.')
|
||||
#parser.add_option('-e', '--open-browser-on-error', dest='open_browser_on_error', action="store_true",
|
||||
# default=False, help='Opens the jenkins page in your browser in case a test fails.')
|
||||
options, args = parser.parse_args(sys.argv)
|
||||
|
||||
if len(args) == 2:
|
||||
if not get_repo_name():
|
||||
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
|
||||
return
|
||||
token = args[-1]
|
||||
if token in OLD_TOKENS:
|
||||
print('Your token is not valid anymore. Get the most recent one.')
|
||||
return
|
||||
jenkins_trigger = JenkinsTrigger(token)
|
||||
try:
|
||||
jenkins_trigger.trigger_build()
|
||||
except HTTPError as e:
|
||||
print("Wrong token.")
|
||||
print('Wrong token.')
|
||||
return
|
||||
# Open the browser before printing the output.
|
||||
if options.open_browser:
|
||||
|
@ -32,12 +32,13 @@ Functional tests to test the AppLocation class and related methods.
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.core.common import de_hump
|
||||
from openlp.core.common import de_hump, trace_error_handler
|
||||
from tests.functional import MagicMock, patch
|
||||
|
||||
|
||||
class TestInitFunctions(TestCase):
|
||||
class TestCommonFunctions(TestCase):
|
||||
"""
|
||||
A test suite to test out various functions in the __init__ class.
|
||||
A test suite to test out various functions in the openlp.core.common module.
|
||||
"""
|
||||
def de_hump_conversion_test(self):
|
||||
"""
|
||||
@ -64,3 +65,19 @@ class TestInitFunctions(TestCase):
|
||||
|
||||
# THEN: the new string should be converted to python format
|
||||
self.assertTrue(new_string == "my_class", 'The class name should have been preserved')
|
||||
|
||||
def trace_error_handler_test(self):
|
||||
"""
|
||||
Test the trace_error_handler() method
|
||||
"""
|
||||
# GIVEN: Mocked out objects
|
||||
with patch('openlp.core.common.traceback') as mocked_traceback:
|
||||
mocked_traceback.extract_stack.return_value = [('openlp.fake', 56, None, 'trace_error_handler_test')]
|
||||
mocked_logger = MagicMock()
|
||||
|
||||
# WHEN: trace_error_handler() is called
|
||||
trace_error_handler(mocked_logger)
|
||||
|
||||
# THEN: The mocked_logger.error() method should have been called with the correct parameters
|
||||
mocked_logger.error.assert_called_with('OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test')
|
||||
|
@ -52,7 +52,7 @@ class TestRegistryProperties(TestCase, RegistryProperties):
|
||||
# GIVEN an Empty Registry
|
||||
# WHEN there is no Application
|
||||
# THEN the application should be none
|
||||
self.assertEquals(self.application, None, 'The application value should be None')
|
||||
self.assertEqual(self.application, None, 'The application value should be None')
|
||||
|
||||
def application_test(self):
|
||||
"""
|
||||
@ -63,4 +63,4 @@ class TestRegistryProperties(TestCase, RegistryProperties):
|
||||
# WHEN the application is registered
|
||||
Registry().register('application', application)
|
||||
# THEN the application should be none
|
||||
self.assertEquals(self.application, application, 'The application value should match')
|
||||
self.assertEqual(self.application, application, 'The application value should match')
|
||||
|
@ -50,8 +50,8 @@ class TestDB(TestCase):
|
||||
"""
|
||||
# GIVEN: Mocked out SQLAlchemy calls and return objects, and an in-memory SQLite database URL
|
||||
with patch('openlp.core.lib.db.create_engine') as mocked_create_engine, \
|
||||
patch('openlp.core.lib.db.MetaData') as MockedMetaData, \
|
||||
patch('openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \
|
||||
patch('openlp.core.lib.db.MetaData') as MockedMetaData, \
|
||||
patch('openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \
|
||||
patch('openlp.core.lib.db.scoped_session') as mocked_scoped_session:
|
||||
mocked_engine = MagicMock()
|
||||
mocked_metadata = MagicMock()
|
||||
|
@ -30,12 +30,16 @@
|
||||
Package to test the openlp.core.ui package.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
from threading import Lock
|
||||
|
||||
from unittest import TestCase
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.lib import ImageManager, ScreenList
|
||||
from openlp.core.lib.imagemanager import Priority
|
||||
from tests.functional import patch
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
|
||||
@ -51,6 +55,8 @@ class TestImageManager(TestCase, TestMixin):
|
||||
self.get_application()
|
||||
ScreenList.create(self.app.desktop())
|
||||
self.image_manager = ImageManager()
|
||||
self.lock = Lock()
|
||||
self.sleep_time = 0.1
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
@ -82,3 +88,87 @@ class TestImageManager(TestCase, TestMixin):
|
||||
with self.assertRaises(KeyError) as context:
|
||||
self.image_manager.get_image(TEST_PATH, 'church1.jpg')
|
||||
self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing image')
|
||||
|
||||
def process_cache_test(self):
|
||||
"""
|
||||
Test the process_cache method
|
||||
"""
|
||||
with patch('openlp.core.lib.imagemanager.resize_image') as mocked_resize_image, \
|
||||
patch('openlp.core.lib.imagemanager.image_to_byte') as mocked_image_to_byte:
|
||||
# GIVEN: Mocked functions
|
||||
mocked_resize_image.side_effect = self.mocked_resize_image
|
||||
mocked_image_to_byte.side_effect = self.mocked_image_to_byte
|
||||
image1 = 'church.jpg'
|
||||
image2 = 'church2.jpg'
|
||||
image3 = 'church3.jpg'
|
||||
image4 = 'church4.jpg'
|
||||
|
||||
# WHEN: Add the images. Then get the lock (=queue can not be processed).
|
||||
self.lock.acquire()
|
||||
self.image_manager.add_image(TEST_PATH, image1, None)
|
||||
self.image_manager.add_image(TEST_PATH, image2, None)
|
||||
|
||||
# THEN: All images have been added to the queue, and only the first image is not be in the list anymore, but
|
||||
# is being processed (see mocked methods/functions).
|
||||
# Note: Priority.Normal means, that the resize_image() was not completed yet (because afterwards the #
|
||||
# priority is adjusted to Priority.Lowest).
|
||||
self.assertEqual(self.get_image_priority(image1), Priority.Normal,
|
||||
"image1's priority should be 'Priority.Normal'")
|
||||
self.assertEqual(self.get_image_priority(image2), Priority.Normal,
|
||||
"image2's priority should be 'Priority.Normal'")
|
||||
|
||||
# WHEN: Add more images.
|
||||
self.image_manager.add_image(TEST_PATH, image3, None)
|
||||
self.image_manager.add_image(TEST_PATH, image4, None)
|
||||
# Allow the queue to process.
|
||||
self.lock.release()
|
||||
# Request some "data".
|
||||
image_bytes = self.image_manager.get_image_bytes(TEST_PATH, image4)
|
||||
image_object = self.image_manager.get_image(TEST_PATH, image3)
|
||||
# Now the mocked methods/functions do not have to sleep anymore.
|
||||
self.sleep_time = 0
|
||||
# Wait for the queue to finish.
|
||||
while not self.image_manager._conversion_queue.empty():
|
||||
time.sleep(0.1)
|
||||
# Because empty() is not reliable, wait a litte; just to make sure.
|
||||
time.sleep(0.1)
|
||||
# THEN: The images' priority reflect how they were processed.
|
||||
self.assertEqual(self.image_manager._conversion_queue.qsize(), 0, "The queue should be empty.")
|
||||
self.assertEqual(self.get_image_priority(image1), Priority.Lowest,
|
||||
"The image should have not been requested (=Lowest)")
|
||||
self.assertEqual(self.get_image_priority(image2), Priority.Lowest,
|
||||
"The image should have not been requested (=Lowest)")
|
||||
self.assertEqual(self.get_image_priority(image3), Priority.Low,
|
||||
"Only the QImage should have been requested (=Low).")
|
||||
self.assertEqual(self.get_image_priority(image4), Priority.Urgent,
|
||||
"The image bytes should have been requested (=Urgent).")
|
||||
|
||||
def get_image_priority(self, image):
|
||||
"""
|
||||
This is a help method to get the priority of the given image out of the image_manager's cache.
|
||||
|
||||
NOTE: This requires, that the image has been added to the image manager using the *TEST_PATH*.
|
||||
|
||||
:param image: The name of the image. E. g. ``image1``
|
||||
"""
|
||||
return self.image_manager._cache[(TEST_PATH, image)].priority
|
||||
|
||||
def mocked_resize_image(self, *args):
|
||||
"""
|
||||
This is a mocked method, so that we can control the work flow of the image manager.
|
||||
"""
|
||||
self.lock.acquire()
|
||||
self.lock.release()
|
||||
# The sleep time is adjusted in the test case.
|
||||
time.sleep(self.sleep_time)
|
||||
return QtGui.QImage()
|
||||
|
||||
def mocked_image_to_byte(self, *args):
|
||||
"""
|
||||
This is a mocked method, so that we can control the work flow of the image manager.
|
||||
"""
|
||||
self.lock.acquire()
|
||||
self.lock.release()
|
||||
# The sleep time is adjusted in the test case.
|
||||
time.sleep(self.sleep_time)
|
||||
return ''
|
@ -212,9 +212,9 @@ class TestPluginManager(TestCase):
|
||||
# WHEN: We run hook_export_menu()
|
||||
plugin_manager.hook_export_menu()
|
||||
|
||||
# THEN: The add_export_menu_Item() method should not have been called
|
||||
self.assertEqual(0, mocked_plugin.add_export_menu_Item.call_count,
|
||||
'The add_export_menu_Item() method should not have been called.')
|
||||
# THEN: The add_export_menu_item() method should not have been called
|
||||
self.assertEqual(0, mocked_plugin.add_export_menu_item.call_count,
|
||||
'The add_export_menu_item() method should not have been called.')
|
||||
|
||||
def hook_export_menu_with_active_plugin_test(self):
|
||||
"""
|
||||
@ -229,8 +229,8 @@ class TestPluginManager(TestCase):
|
||||
# WHEN: We run hook_export_menu()
|
||||
plugin_manager.hook_export_menu()
|
||||
|
||||
# THEN: The add_export_menu_Item() method should have been called
|
||||
mocked_plugin.add_export_menu_Item.assert_called_with(self.mocked_main_window.file_export_menu)
|
||||
# THEN: The add_export_menu_item() method should have been called
|
||||
mocked_plugin.add_export_menu_item.assert_called_with(self.mocked_main_window.file_export_menu)
|
||||
|
||||
def hook_upgrade_plugin_settings_with_disabled_plugin_test(self):
|
||||
"""
|
||||
@ -264,7 +264,7 @@ class TestPluginManager(TestCase):
|
||||
# WHEN: We run hook_upgrade_plugin_settings()
|
||||
plugin_manager.hook_upgrade_plugin_settings(settings)
|
||||
|
||||
# THEN: The add_export_menu_Item() method should have been called
|
||||
# THEN: The add_export_menu_item() method should have been called
|
||||
mocked_plugin.upgrade_settings.assert_called_with(settings)
|
||||
|
||||
def hook_tools_menu_with_disabled_plugin_test(self):
|
||||
|
@ -49,7 +49,7 @@ class TestRenderer(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up the components need for all tests.
|
||||
Set up the components need for all tests
|
||||
"""
|
||||
# Mocked out desktop object
|
||||
self.desktop = MagicMock()
|
||||
@ -67,7 +67,7 @@ class TestRenderer(TestCase):
|
||||
|
||||
def initial_renderer_test(self):
|
||||
"""
|
||||
Test the initial renderer state .
|
||||
Test the initial renderer state
|
||||
"""
|
||||
# GIVEN: A new renderer instance.
|
||||
renderer = Renderer()
|
||||
@ -77,7 +77,7 @@ class TestRenderer(TestCase):
|
||||
|
||||
def default_screen_layout_test(self):
|
||||
"""
|
||||
Test the default layout calculations.
|
||||
Test the default layout calculations
|
||||
"""
|
||||
# GIVEN: A new renderer instance.
|
||||
renderer = Renderer()
|
||||
@ -87,3 +87,35 @@ class TestRenderer(TestCase):
|
||||
self.assertEqual(renderer.height, 768, 'The base renderer should be a live controller')
|
||||
self.assertEqual(renderer.screen_ratio, 0.75, 'The base renderer should be a live controller')
|
||||
self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller')
|
||||
|
||||
def _get_start_tags_test(self):
|
||||
"""
|
||||
Test the _get_start_tags() method
|
||||
"""
|
||||
# GIVEN: A new renderer instance. Broken raw_text (missing closing tags).
|
||||
renderer = Renderer()
|
||||
given_raw_text = '{st}{r}Text text text'
|
||||
expected_tuple = ('{st}{r}Text text text{/r}{/st}', '{st}{r}',
|
||||
'<strong><span style="-webkit-text-fill-color:red">')
|
||||
|
||||
# WHEN:
|
||||
result = renderer._get_start_tags(given_raw_text)
|
||||
|
||||
# THEN: Check if the correct tuple is returned.
|
||||
self.assertEqual(result, expected_tuple), 'A tuple should be returned containing the text with correct ' \
|
||||
'tags, the opening tags, and the opening html tags.'
|
||||
|
||||
def _word_split_test(self):
|
||||
"""
|
||||
Test the _word_split() method
|
||||
"""
|
||||
# GIVEN: A line of text
|
||||
renderer = Renderer()
|
||||
given_line = 'beginning asdf \n end asdf'
|
||||
expected_words = ['beginning', 'asdf', 'end', 'asdf']
|
||||
|
||||
# WHEN: Split the line
|
||||
result_words = renderer._words_split(given_line)
|
||||
|
||||
# THEN: The word lists should be the same.
|
||||
self.assertListEqual(result_words, expected_words)
|
||||
|
@ -81,3 +81,92 @@ class TestUi(TestCase):
|
||||
self.assertIsInstance(btnbox, QtGui.QDialogButtonBox)
|
||||
self.assertEqual(1, len(btnbox.buttons()))
|
||||
self.assertEqual(QtGui.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0]))
|
||||
|
||||
def test_create_button(self):
|
||||
"""
|
||||
Test creating a button
|
||||
"""
|
||||
# GIVEN: A dialog
|
||||
dialog = QtGui.QDialog()
|
||||
|
||||
# WHEN: We create the button
|
||||
btn = create_button(dialog, 'my_btn')
|
||||
|
||||
# THEN: We should get a button with a name
|
||||
self.assertIsInstance(btn, QtGui.QPushButton)
|
||||
self.assertEqual('my_btn', btn.objectName())
|
||||
self.assertTrue(btn.isEnabled())
|
||||
|
||||
# WHEN: We create a button with some attributes
|
||||
btn = create_button(dialog, 'my_btn', text='Hello', tooltip='How are you?', enabled=False)
|
||||
|
||||
# THEN: We should get a button with those attributes
|
||||
self.assertIsInstance(btn, QtGui.QPushButton)
|
||||
self.assertEqual('Hello', btn.text())
|
||||
self.assertEqual('How are you?', btn.toolTip())
|
||||
self.assertFalse(btn.isEnabled())
|
||||
|
||||
# WHEN: We create a toolbutton
|
||||
btn = create_button(dialog, 'my_btn', btn_class='toolbutton')
|
||||
|
||||
# THEN: We should get a toolbutton
|
||||
self.assertIsInstance(btn, QtGui.QToolButton)
|
||||
self.assertEqual('my_btn', btn.objectName())
|
||||
self.assertTrue(btn.isEnabled())
|
||||
|
||||
def test_create_valign_selection_widgets(self):
|
||||
"""
|
||||
Test creating a combo box for valign selection
|
||||
"""
|
||||
# GIVEN: A dialog
|
||||
dialog = QtGui.QDialog()
|
||||
|
||||
# WHEN: We create the widgets
|
||||
label, combo = create_valign_selection_widgets(dialog)
|
||||
|
||||
# THEN: We should get a label and a combobox.
|
||||
self.assertEqual(translate('OpenLP.Ui', '&Vertical Align:'), label.text())
|
||||
self.assertIsInstance(combo, QtGui.QComboBox)
|
||||
self.assertEqual(combo, label.buddy())
|
||||
for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]:
|
||||
self.assertTrue(combo.findText(text) >= 0)
|
||||
|
||||
def test_create_horizontal_adjusting_combo_box(self):
|
||||
"""
|
||||
Test creating a horizontal adjusting combo box
|
||||
"""
|
||||
# GIVEN: A dialog
|
||||
dialog = QtGui.QDialog()
|
||||
|
||||
# WHEN: We create the combobox
|
||||
combo = create_horizontal_adjusting_combo_box(dialog, 'combo1')
|
||||
|
||||
# THEN: We should get a ComboBox
|
||||
self.assertIsInstance(combo, QtGui.QComboBox)
|
||||
self.assertEqual('combo1', combo.objectName())
|
||||
self.assertEqual(QtGui.QComboBox.AdjustToMinimumContentsLength, combo.sizeAdjustPolicy())
|
||||
|
||||
def test_create_action(self):
|
||||
"""
|
||||
Test creating an action
|
||||
"""
|
||||
# GIVEN: A dialog
|
||||
dialog = QtGui.QDialog()
|
||||
|
||||
# WHEN: We create an action
|
||||
action = create_action(dialog, 'my_action')
|
||||
|
||||
# THEN: We should get a QAction
|
||||
self.assertIsInstance(action, QtGui.QAction)
|
||||
self.assertEqual('my_action', action.objectName())
|
||||
|
||||
# WHEN: We create an action with some properties
|
||||
action = create_action(dialog, 'my_action', text='my text', icon=':/wizards/wizard_firsttime.bmp',
|
||||
tooltip='my tooltip', statustip='my statustip')
|
||||
|
||||
# THEN: These properties should be set
|
||||
self.assertIsInstance(action, QtGui.QAction)
|
||||
self.assertEqual('my text', action.text())
|
||||
self.assertIsInstance(action.icon(), QtGui.QIcon)
|
||||
self.assertEqual('my tooltip', action.toolTip())
|
||||
self.assertEqual('my statustip', action.statusTip())
|
||||
|
72
tests/functional/openlp_core_ui/test_firsttimeform.py
Normal file
72
tests/functional/openlp_core_ui/test_firsttimeform.py
Normal file
@ -0,0 +1,72 @@
|
||||
# -*- 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.firsttimeform package.
|
||||
"""
|
||||
from unittest import TestCase
|
||||
|
||||
from tests.functional import MagicMock
|
||||
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||
|
||||
|
||||
class TestFirstTimeForm(TestCase, TestMixin):
|
||||
|
||||
def setUp(self):
|
||||
screens = MagicMock()
|
||||
self.get_application()
|
||||
Registry.create()
|
||||
Registry().register('application', self.app)
|
||||
self.first_time_form = FirstTimeForm(screens)
|
||||
|
||||
def test_access_to_config(self):
|
||||
"""
|
||||
Test if we can access the First Time Form's config file
|
||||
"""
|
||||
# GIVEN A new First Time Form instance.
|
||||
|
||||
# WHEN The default First Time Form is built.
|
||||
|
||||
# THEN The First Time Form web configuration file should be accessable.
|
||||
self.assertTrue(self.first_time_form.web_access,
|
||||
'First Time Wizard\'s web configuration file should be available')
|
||||
|
||||
def test_parsable_config(self):
|
||||
"""
|
||||
Test if the First Time Form's config file is parsable
|
||||
"""
|
||||
# GIVEN A new First Time Form instance.
|
||||
|
||||
# WHEN The default First Time Form is built.
|
||||
|
||||
# THEN The First Time Form web configuration file should be parsable
|
||||
self.assertTrue(self.first_time_form.songs_url,
|
||||
'First Time Wizard\'s web configuration file should be parsable')
|
@ -79,3 +79,31 @@ class TestMainDisplay(TestCase):
|
||||
|
||||
# THEN: The controller should not be a live controller.
|
||||
self.assertEqual(main_display.is_live, True, 'The main display should be a live controller')
|
||||
|
||||
def set_transparency_test(self):
|
||||
"""
|
||||
Test creating an instance of the MainDisplay class
|
||||
"""
|
||||
# GIVEN: get an instance of MainDisplay
|
||||
display = MagicMock()
|
||||
main_display = MainDisplay(display)
|
||||
|
||||
# WHEN: We enable transparency
|
||||
main_display.set_transparency(True)
|
||||
|
||||
# THEN: There should be a Stylesheet
|
||||
self.assertEqual('QGraphicsView {background: transparent; border: 0px;}', main_display.styleSheet(),
|
||||
'MainDisplay instance should be transparent')
|
||||
self.assertFalse(main_display.autoFillBackground(),
|
||||
'MainDisplay instance should be without background auto fill')
|
||||
self.assertTrue(main_display.testAttribute(QtCore.Qt.WA_TranslucentBackground),
|
||||
'MainDisplay hasnt translucent background')
|
||||
|
||||
# WHEN: We disable transparency
|
||||
main_display.set_transparency(False)
|
||||
|
||||
# THEN: The Stylesheet should be empty
|
||||
self.assertEqual('QGraphicsView {}', main_display.styleSheet(),
|
||||
'MainDisplay instance should not be transparent')
|
||||
self.assertFalse(main_display.testAttribute(QtCore.Qt.WA_TranslucentBackground),
|
||||
'MainDisplay hasnt translucent background')
|
||||
|
97
tests/functional/openlp_core_ui/test_mainwindow.py
Normal file
97
tests/functional/openlp_core_ui/test_mainwindow.py
Normal file
@ -0,0 +1,97 @@
|
||||
# -*- 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 openlp.core.ui.mainwindow package.
|
||||
"""
|
||||
import os
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.core.ui.mainwindow import MainWindow
|
||||
from openlp.core.common.registry import Registry
|
||||
from tests.utils.constants import TEST_RESOURCES_PATH
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
from tests.functional import MagicMock, patch
|
||||
|
||||
|
||||
class TestMainWindow(TestCase, TestMixin):
|
||||
|
||||
def setUp(self):
|
||||
Registry.create()
|
||||
self.registry = Registry()
|
||||
self.get_application()
|
||||
# Mock cursor busy/normal methods.
|
||||
self.app.set_busy_cursor = MagicMock()
|
||||
self.app.set_normal_cursor = MagicMock()
|
||||
self.app.args = []
|
||||
Registry().register('application', self.app)
|
||||
# Mock classes and methods used by mainwindow.
|
||||
with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \
|
||||
patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \
|
||||
patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \
|
||||
patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \
|
||||
patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \
|
||||
patch('openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \
|
||||
patch('openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \
|
||||
patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \
|
||||
patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer:
|
||||
self.main_window = MainWindow()
|
||||
|
||||
def tearDown(self):
|
||||
del self.main_window
|
||||
|
||||
def cmd_line_file_test(self):
|
||||
"""
|
||||
Test that passing a service file from the command line loads the service.
|
||||
"""
|
||||
# GIVEN a service as an argument to openlp
|
||||
service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz')
|
||||
self.main_window.arguments = [service]
|
||||
with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path:
|
||||
|
||||
# WHEN the argument is processed
|
||||
self.main_window.open_cmd_line_files()
|
||||
|
||||
# THEN the service from the arguments is loaded
|
||||
mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path'
|
||||
|
||||
def cmd_line_arg_test(self):
|
||||
"""
|
||||
Test that passing a non service file does nothing.
|
||||
"""
|
||||
# GIVEN a non service file as an argument to openlp
|
||||
service = os.path.join('openlp.py')
|
||||
self.main_window.arguments = [service]
|
||||
with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path:
|
||||
|
||||
# WHEN the argument is processed
|
||||
self.main_window.open_cmd_line_files()
|
||||
|
||||
# THEN the file should not be opened
|
||||
assert not mocked_load_path.called, 'load_path should not have been called'
|
@ -180,4 +180,4 @@ class TestBSExtract(TestCase):
|
||||
'http://m.bibleserver.com/overlay/selectBook?translation=NIV')
|
||||
self.assertFalse(self.mock_log.error.called, 'log.error should not have been called')
|
||||
self.assertFalse(self.mock_send_error_message.called, 'send_error_message should not have been called')
|
||||
self.assertEquals(result, ['Genesis', 'Leviticus'])
|
||||
self.assertEqual(result, ['Genesis', 'Leviticus'])
|
||||
|
@ -153,10 +153,10 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
|
||||
# THEN:
|
||||
self.assertIsNotNone(field_desc_entry, 'Import should not be none')
|
||||
self.assertEquals(field_desc_entry.name, name, 'FieldDescEntry.name should be the same as the name argument')
|
||||
self.assertEquals(field_desc_entry.field_type, field_type,
|
||||
self.assertEqual(field_desc_entry.name, name, 'FieldDescEntry.name should be the same as the name argument')
|
||||
self.assertEqual(field_desc_entry.field_type, field_type,
|
||||
'FieldDescEntry.type should be the same as the type argument')
|
||||
self.assertEquals(field_desc_entry.size, size, 'FieldDescEntry.size should be the same as the size argument')
|
||||
self.assertEqual(field_desc_entry.size, size, 'FieldDescEntry.size should be the same as the size argument')
|
||||
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
@ -188,7 +188,7 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
for field_name in existing_fields:
|
||||
|
||||
# THEN: The item corresponding the index returned should have the same name attribute
|
||||
self.assertEquals(importer.field_descriptions[importer.find_field(field_name)].name, field_name)
|
||||
self.assertEqual(importer.field_descriptions[importer.find_field(field_name)].name, field_name)
|
||||
|
||||
def find_non_existing_field_test(self):
|
||||
"""
|
||||
@ -244,7 +244,7 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
return_value = importer.get_field(field_index)
|
||||
|
||||
# THEN: get_field should return the known results
|
||||
self.assertEquals(return_value, result,
|
||||
self.assertEqual(return_value, result,
|
||||
'get_field should return "%s" when called with "%s"' %
|
||||
(result, TEST_FIELDS[field_index]))
|
||||
|
||||
@ -271,7 +271,7 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
get_field_seek_calls = test_results[2]['seek']
|
||||
|
||||
# THEN: get_field should return the appropriate value with the appropriate mocked objects being called
|
||||
self.assertEquals(importer.get_field(field_index), get_field_result)
|
||||
self.assertEqual(importer.get_field(field_index), get_field_result)
|
||||
for call in get_field_read_calls:
|
||||
mocked_memo_file.read.assert_any_call(call)
|
||||
for call in get_field_seek_calls:
|
||||
@ -417,12 +417,12 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
if song_copyright:
|
||||
self.assertEqual(importer.copyright, song_copyright)
|
||||
if ccli_number:
|
||||
self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s'
|
||||
self.assertEqual(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s'
|
||||
% (title, ccli_number))
|
||||
for verse_text, verse_tag in add_verse_calls:
|
||||
mocked_add_verse.assert_any_call(verse_text, verse_tag)
|
||||
if verse_order_list:
|
||||
self.assertEquals(importer.verse_order_list, verse_order_list,
|
||||
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()
|
||||
|
||||
|
@ -96,10 +96,10 @@ class TestLib(TestCase):
|
||||
self.song2.search_lyrics = self.full_lyrics
|
||||
|
||||
# WHEN: We compare those songs for equality.
|
||||
result = songs_probably_equal(self.song1, self.song2)
|
||||
result = songs_probably_equal((self.song1, self.song2))
|
||||
|
||||
# THEN: The result should be True.
|
||||
assert result is True, 'The result should be True'
|
||||
# THEN: The result should be a tuple..
|
||||
assert result == (self.song1, self.song2), 'The result should be the tuble of songs'
|
||||
|
||||
def songs_probably_equal_short_song_test(self):
|
||||
"""
|
||||
@ -110,10 +110,10 @@ class TestLib(TestCase):
|
||||
self.song2.search_lyrics = self.short_lyrics
|
||||
|
||||
# WHEN: We compare those songs for equality.
|
||||
result = songs_probably_equal(self.song1, self.song2)
|
||||
result = songs_probably_equal((self.song1, self.song2))
|
||||
|
||||
# THEN: The result should be True.
|
||||
assert result is True, 'The result should be True'
|
||||
# THEN: The result should be a tuple..
|
||||
assert result == (self.song1, self.song2), 'The result should be the tuble of songs'
|
||||
|
||||
def songs_probably_equal_error_song_test(self):
|
||||
"""
|
||||
@ -124,10 +124,11 @@ class TestLib(TestCase):
|
||||
self.song2.search_lyrics = self.error_lyrics
|
||||
|
||||
# WHEN: We compare those songs for equality.
|
||||
result = songs_probably_equal(self.song1, self.song2)
|
||||
result = songs_probably_equal((self.song1, self.song2))
|
||||
|
||||
# THEN: The result should be a tuple of songs..
|
||||
assert result == (self.song1, self.song2), 'The result should be the tuble of songs'
|
||||
|
||||
# THEN: The result should be True.
|
||||
assert result is True, 'The result should be True'
|
||||
|
||||
def songs_probably_equal_different_song_test(self):
|
||||
"""
|
||||
@ -138,10 +139,10 @@ class TestLib(TestCase):
|
||||
self.song2.search_lyrics = self.different_lyrics
|
||||
|
||||
# WHEN: We compare those songs for equality.
|
||||
result = songs_probably_equal(self.song1, self.song2)
|
||||
result = songs_probably_equal((self.song1, self.song2))
|
||||
|
||||
# THEN: The result should be False.
|
||||
assert result is False, 'The result should be False'
|
||||
# THEN: The result should be None.
|
||||
assert result is None, 'The result should be None'
|
||||
|
||||
def remove_typos_beginning_test(self):
|
||||
"""
|
||||
|
@ -35,6 +35,7 @@ from unittest import TestCase
|
||||
|
||||
from tests.functional import MagicMock, patch
|
||||
from openlp.plugins.songs.lib.songbeamerimport import SongBeamerImport
|
||||
from openlp.plugins.songs.lib import VerseType
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||
'..', '..', '..', 'resources', 'songbeamersongs'))
|
||||
@ -89,7 +90,7 @@ class TestSongBeamerImport(TestCase):
|
||||
|
||||
# THEN: do_import should return none and the progress bar maximum should not be set.
|
||||
self.assertIsNone(importer.do_import(), 'do_import should return None when import_source is not a list')
|
||||
self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
|
||||
self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False,
|
||||
'setMaxium on import_wizard.progress_bar should not have been called')
|
||||
|
||||
def valid_import_source_test(self):
|
||||
@ -143,13 +144,90 @@ class TestSongBeamerImport(TestCase):
|
||||
# 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.assertEquals(importer.title, title, 'title for %s should be "%s"' % (song_file, title))
|
||||
self.assertEqual(importer.title, title, 'title for %s should be "%s"' % (song_file, title))
|
||||
for verse_text, verse_tag in add_verse_calls:
|
||||
mocked_add_verse.assert_any_call(verse_text, verse_tag)
|
||||
if song_book_name:
|
||||
self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' %
|
||||
self.assertEqual(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' %
|
||||
(song_file, song_book_name))
|
||||
if song_number:
|
||||
self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s' %
|
||||
self.assertEqual(importer.song_number, song_number, 'song_number for %s should be %s' %
|
||||
(song_file, song_number))
|
||||
mocked_finish.assert_called_with()
|
||||
|
||||
def check_verse_marks_test(self):
|
||||
"""
|
||||
Tests different lines to see if a verse mark is detected or not
|
||||
"""
|
||||
|
||||
# GIVEN: line with unnumbered verse-type
|
||||
line = 'Refrain'
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back true and c as self.current_verse_type
|
||||
self.assertTrue(result, 'Versemark for <Refrain> should be found, value true')
|
||||
self.assertEqual(self.current_verse_type, 'c', '<Refrain> should be interpreted as <c>')
|
||||
|
||||
# GIVEN: line with unnumbered verse-type and trailing space
|
||||
line = 'Refrain '
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back true and c as self.current_verse_type
|
||||
self.assertTrue(result, 'Versemark for <Refrain > should be found, value true')
|
||||
self.assertEqual(self.current_verse_type, 'c', '<Refrain > should be interpreted as <c>')
|
||||
|
||||
# GIVEN: line with numbered verse-type
|
||||
line = 'Verse 1'
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back true and v1 as self.current_verse_type
|
||||
self.assertTrue(result, 'Versemark for <Verse 1> should be found, value true')
|
||||
self.assertEqual(self.current_verse_type, 'v1', u'<Verse 1> should be interpreted as <v1>')
|
||||
|
||||
# GIVEN: line with special unnumbered verse-mark (used in Songbeamer to allow usage of non-supported tags)
|
||||
line = '$$M=special'
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back true and o as self.current_verse_type
|
||||
self.assertTrue(result, 'Versemark for <$$M=special> should be found, value true')
|
||||
self.assertEqual(self.current_verse_type, 'o', u'<$$M=special> should be interpreted as <o>')
|
||||
|
||||
# GIVEN: line with song-text with 3 words
|
||||
line = 'Jesus my saviour'
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back false and none as self.current_verse_type
|
||||
self.assertFalse(result, 'No versemark for <Jesus my saviour> should be found, value false')
|
||||
self.assertIsNone(self.current_verse_type, '<Jesus my saviour> should be interpreted as none versemark')
|
||||
|
||||
# GIVEN: line with song-text with 2 words
|
||||
line = 'Praise him'
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back false and none as self.current_verse_type
|
||||
self.assertFalse(result, 'No versemark for <Praise him> should be found, value false')
|
||||
self.assertIsNone(self.current_verse_type, '<Praise him> should be interpreted as none versemark')
|
||||
|
||||
# GIVEN: line with only a space (could occur, nothing regular)
|
||||
line = ' '
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back false and none as self.current_verse_type
|
||||
self.assertFalse(result, 'No versemark for < > should be found, value false')
|
||||
self.assertIsNone(self.current_verse_type, '< > should be interpreted as none versemark')
|
||||
|
||||
# GIVEN: blank line (could occur, nothing regular)
|
||||
line = ''
|
||||
self.current_verse_type = None
|
||||
# WHEN: line is being checked for verse marks
|
||||
result = SongBeamerImport.check_verse_marks(self, line)
|
||||
# THEN: we should get back false and none as self.current_verse_type
|
||||
self.assertFalse(result, 'No versemark for <> should be found, value false')
|
||||
self.assertIsNone(self.current_verse_type, '<> should be interpreted as none versemark')
|
||||
|
@ -95,7 +95,7 @@ class TestSongShowPlusImport(TestCase):
|
||||
|
||||
# THEN: do_import should return none and the progress bar maximum should not be set.
|
||||
self.assertIsNone(importer.do_import(), 'do_import should return None when import_source is not a list')
|
||||
self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
|
||||
self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False,
|
||||
'setMaximum on import_wizard.progress_bar should not have been called')
|
||||
|
||||
def valid_import_source_test(self):
|
||||
@ -143,7 +143,7 @@ class TestSongShowPlusImport(TestCase):
|
||||
|
||||
# THEN: The returned value should should correlate with the input arguments
|
||||
for original_tag, openlp_tag in test_values:
|
||||
self.assertEquals(importer.to_openlp_verse_tag(original_tag), openlp_tag,
|
||||
self.assertEqual(importer.to_openlp_verse_tag(original_tag), openlp_tag,
|
||||
'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' %
|
||||
(openlp_tag, original_tag))
|
||||
|
||||
@ -172,6 +172,6 @@ class TestSongShowPlusImport(TestCase):
|
||||
|
||||
# THEN: The returned value should should correlate with the input arguments
|
||||
for original_tag, openlp_tag in test_values:
|
||||
self.assertEquals(importer.to_openlp_verse_tag(original_tag, ignore_unique=True), openlp_tag,
|
||||
self.assertEqual(importer.to_openlp_verse_tag(original_tag, ignore_unique=True), openlp_tag,
|
||||
'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' %
|
||||
(openlp_tag, original_tag))
|
||||
|
56
tests/functional/openlp_plugins/songs/test_zionworximport.py
Normal file
56
tests/functional/openlp_plugins/songs/test_zionworximport.py
Normal 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-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 #
|
||||
###############################################################################
|
||||
"""
|
||||
This module contains tests for the ZionWorx song importer.
|
||||
"""
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from tests.functional import MagicMock, patch
|
||||
from openlp.plugins.songs.lib.zionworximport import ZionWorxImport
|
||||
from openlp.plugins.songs.lib.songimport import SongImport
|
||||
|
||||
|
||||
class TestZionWorxImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`zionworximport` module.
|
||||
"""
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
Test creating an instance of the ZionWorx file importer
|
||||
"""
|
||||
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||
with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'):
|
||||
mocked_manager = MagicMock()
|
||||
|
||||
# WHEN: An importer object is created
|
||||
importer = ZionWorxImport(mocked_manager, filenames=[])
|
||||
|
||||
# THEN: The importer should be an instance of SongImport
|
||||
self.assertIsInstance(importer, SongImport)
|
@ -110,29 +110,29 @@ class SongImportTestHelper(TestCase):
|
||||
# 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.assertEquals(importer.title, title, 'title for %s should be "%s"' % (source_file_name, title))
|
||||
self.assertEqual(importer.title, title, 'title for %s should be "%s"' % (source_file_name, title))
|
||||
for author in author_calls:
|
||||
self.mocked_parse_author.assert_any_call(author)
|
||||
if song_copyright:
|
||||
self.mocked_add_copyright.assert_called_with(song_copyright)
|
||||
if ccli_number:
|
||||
self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' %
|
||||
self.assertEqual(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' %
|
||||
(source_file_name, ccli_number))
|
||||
for verse_text, verse_tag in add_verse_calls:
|
||||
self.mocked_add_verse.assert_any_call(verse_text, verse_tag)
|
||||
if topics:
|
||||
self.assertEquals(importer.topics, topics, 'topics for %s should be %s' % (source_file_name, topics))
|
||||
self.assertEqual(importer.topics, topics, 'topics for %s should be %s' % (source_file_name, topics))
|
||||
if comments:
|
||||
self.assertEquals(importer.comments, comments, 'comments for %s should be "%s"' %
|
||||
self.assertEqual(importer.comments, comments, 'comments for %s should be "%s"' %
|
||||
(source_file_name, comments))
|
||||
if song_book_name:
|
||||
self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' %
|
||||
self.assertEqual(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"' %
|
||||
(source_file_name, song_book_name))
|
||||
if song_number:
|
||||
self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s' %
|
||||
self.assertEqual(importer.song_number, song_number, 'song_number for %s should be %s' %
|
||||
(source_file_name, song_number))
|
||||
if verse_order_list:
|
||||
self.assertEquals(importer.verse_order_list, [], 'verse_order_list for %s should be %s' %
|
||||
self.assertEqual(importer.verse_order_list, [], 'verse_order_list for %s should be %s' %
|
||||
(source_file_name, verse_order_list))
|
||||
self.mocked_finish.assert_called_with()
|
||||
|
||||
|
@ -313,6 +313,7 @@ class TestServiceManager(TestCase, TestMixin):
|
||||
self.service_manager.notes_action.setVisible = MagicMock()
|
||||
self.service_manager.time_action.setVisible = MagicMock()
|
||||
self.service_manager.auto_start_action.setVisible = MagicMock()
|
||||
self.service_manager.rename_action.setVisible = MagicMock()
|
||||
|
||||
# WHEN: Show the context menu.
|
||||
self.service_manager.context_menu(q_point)
|
||||
@ -329,6 +330,8 @@ class TestServiceManager(TestCase, TestMixin):
|
||||
'The action should be set invisible.'
|
||||
self.service_manager.auto_start_action.setVisible.assert_called_with(True), \
|
||||
'The action should be set visible.'
|
||||
self.service_manager.rename_action.setVisible.assert_called_once_with(False), \
|
||||
'The action should be set invisible.'
|
||||
|
||||
def click_on_new_service_test(self):
|
||||
"""
|
||||
|
60
tests/interfaces/openlp_core_ui/test_splashscreen.py
Normal file
60
tests/interfaces/openlp_core_ui/test_splashscreen.py
Normal file
@ -0,0 +1,60 @@
|
||||
# -*- 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
Test the openlp.core.ui.splashscreen class.
|
||||
"""
|
||||
from unittest import TestCase
|
||||
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from openlp.core.ui import SplashScreen
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
class TestSplashScreen(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
self.get_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
|
||||
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
|
||||
|
||||
def setupUi_test(self):
|
||||
"""
|
||||
Test if the setupUi method....
|
||||
"""
|
||||
# GIVEN: A splash screen instance.
|
||||
splash = SplashScreen()
|
||||
|
||||
# THEN: Check if the splash has a setupUi method.
|
||||
assert hasattr(splash, 'setupUi'), 'The Splash Screen should have a setupUi() method.'
|
@ -83,7 +83,7 @@ class TestBibleManager(TestCase, TestMixin):
|
||||
# WHEN asking to parse the bible reference
|
||||
results = parse_reference('1 Timothy 1', self.manager.db_cache['tests'], MagicMock(), 54)
|
||||
# THEN a verse array should be returned
|
||||
self.assertEquals([(54, 1, 1, -1)], results, "The bible verses should matches the expected results")
|
||||
self.assertEqual([(54, 1, 1, -1)], results, "The bible verses should matches the expected results")
|
||||
|
||||
def parse_reference_two_test(self):
|
||||
"""
|
||||
@ -93,7 +93,7 @@ class TestBibleManager(TestCase, TestMixin):
|
||||
# WHEN asking to parse the bible reference
|
||||
results = parse_reference('1 Timothy 1:1-2', self.manager.db_cache['tests'], MagicMock(), 54)
|
||||
# THEN a verse array should be returned
|
||||
self.assertEquals([(54, 1, 1, 2)], results, "The bible verses should matches the expected results")
|
||||
self.assertEqual([(54, 1, 1, 2)], results, "The bible verses should matches the expected results")
|
||||
|
||||
def parse_reference_three_test(self):
|
||||
"""
|
||||
@ -103,5 +103,5 @@ class TestBibleManager(TestCase, TestMixin):
|
||||
# WHEN asking to parse the bible reference
|
||||
results = parse_reference('1 Timothy 1:1-2:1', self.manager.db_cache['tests'], MagicMock(), 54)
|
||||
# THEN a verse array should be returned
|
||||
self.assertEquals([(54, 1, 1, -1), (54, 2, 1, 1)], results, "The bible verses should matches the expected "
|
||||
self.assertEqual([(54, 1, 1, -1), (54, 2, 1, 1)], results, "The bible verses should matches the expected "
|
||||
"results")
|
||||
|
BIN
tests/resources/church2.jpg
Normal file
BIN
tests/resources/church2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 213 KiB |
BIN
tests/resources/church3.jpg
Normal file
BIN
tests/resources/church3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 213 KiB |
BIN
tests/resources/church4.jpg
Normal file
BIN
tests/resources/church4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 213 KiB |
BIN
tests/resources/service/test.osz
Normal file
BIN
tests/resources/service/test.osz
Normal file
Binary file not shown.
75
tests/utils/test_bzr_tags.py
Normal file
75
tests/utils/test_bzr_tags.py
Normal 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-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 for proper bzr tags.
|
||||
"""
|
||||
import os
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
TAGS = [
|
||||
['1.9.0', '1'],
|
||||
['1.9.1', '775'],
|
||||
['1.9.2', '890'],
|
||||
['1.9.3', '1063'],
|
||||
['1.9.4', '1196'],
|
||||
['1.9.5', '1421'],
|
||||
['1.9.6', '1657'],
|
||||
['1.9.7', '1761'],
|
||||
['1.9.8', '1856'],
|
||||
['1.9.9', '1917'],
|
||||
['1.9.10', '2003'],
|
||||
['1.9.11', '2039'],
|
||||
['1.9.12', '2063'],
|
||||
['2.0', '2118'],
|
||||
['2.0.1', '?'],
|
||||
['2.0.2', '?'],
|
||||
['2.0.3', '?'],
|
||||
['2.1.0', '2119']
|
||||
]
|
||||
|
||||
|
||||
class TestBzrTags(TestCase):
|
||||
|
||||
def bzr_tags_test(self):
|
||||
"""
|
||||
Test for proper bzr tags
|
||||
"""
|
||||
# GIVEN: A bzr branch
|
||||
path = os.path.dirname(__file__)
|
||||
|
||||
# WHEN getting the branches tags
|
||||
bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE)
|
||||
stdout = bzr.communicate()[0]
|
||||
tags = [line.decode('utf-8').split() for line in stdout.splitlines()]
|
||||
|
||||
# THEN the tags should match the accepted tags
|
||||
self.assertEqual(TAGS, tags, 'List of tags should match')
|
Loading…
Reference in New Issue
Block a user