forked from openlp/openlp
- Merged trunk on 23.12.16
This commit is contained in:
commit
a9520ced68
@ -1 +1 @@
|
||||
2.4
|
||||
2.5.0
|
||||
|
@ -129,21 +129,21 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||
application_stylesheet += WIN_REPAIR_STYLESHEET
|
||||
if application_stylesheet:
|
||||
self.setStyleSheet(application_stylesheet)
|
||||
show_splash = Settings().value('core/show splash')
|
||||
if show_splash:
|
||||
can_show_splash = Settings().value('core/show splash')
|
||||
if can_show_splash:
|
||||
self.splash = SplashScreen()
|
||||
self.splash.show()
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
# Check if OpenLP has been upgrade and if a backup of data should be created
|
||||
self.backup_on_upgrade(has_run_wizard)
|
||||
self.backup_on_upgrade(has_run_wizard, can_show_splash)
|
||||
# start the main app window
|
||||
self.main_window = MainWindow()
|
||||
Registry().execute('bootstrap_initialise')
|
||||
Registry().execute('bootstrap_post_set_up')
|
||||
Registry().initialise = False
|
||||
self.main_window.show()
|
||||
if show_splash:
|
||||
if can_show_splash:
|
||||
# now kill the splashscreen
|
||||
self.splash.finish(self.main_window)
|
||||
log.debug('Splashscreen closed')
|
||||
@ -224,13 +224,20 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||
self.exception_form = ExceptionForm()
|
||||
self.exception_form.exception_text_edit.setPlainText(''.join(format_exception(exc_type, value, traceback)))
|
||||
self.set_normal_cursor()
|
||||
is_splash_visible = False
|
||||
if hasattr(self, 'splash') and self.splash.isVisible():
|
||||
is_splash_visible = True
|
||||
self.splash.hide()
|
||||
self.exception_form.exec()
|
||||
if is_splash_visible:
|
||||
self.splash.show()
|
||||
|
||||
def backup_on_upgrade(self, has_run_wizard):
|
||||
def backup_on_upgrade(self, has_run_wizard, can_show_splash):
|
||||
"""
|
||||
Check if OpenLP has been upgraded, and ask if a backup of data should be made
|
||||
|
||||
:param has_run_wizard: OpenLP has been run before
|
||||
:param can_show_splash: Should OpenLP show the splash screen
|
||||
"""
|
||||
data_version = Settings().value('core/application version')
|
||||
openlp_version = get_application_version()['version']
|
||||
@ -239,6 +246,8 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
# If data_version is different from the current version ask if we should backup the data folder
|
||||
elif data_version != openlp_version:
|
||||
if self.splash.isVisible():
|
||||
self.splash.hide()
|
||||
if QtWidgets.QMessageBox.question(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'OpenLP has been upgraded, do you want to create\n'
|
||||
'a backup of the old data folder?'),
|
||||
@ -261,6 +270,8 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||
|
||||
# Update the version in the settings
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
if can_show_splash:
|
||||
self.splash.show()
|
||||
|
||||
def process_events(self):
|
||||
"""
|
||||
@ -375,6 +386,7 @@ def main(args=None):
|
||||
application.setOrganizationName('OpenLP')
|
||||
application.setOrganizationDomain('openlp.org')
|
||||
application.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
|
||||
application.setAttribute(QtCore.Qt.AA_DontCreateNativeWidgetSiblings, True)
|
||||
if args and args.portable:
|
||||
application.setApplicationName('OpenLPPortable')
|
||||
Settings.setDefaultFormat(Settings.IniFormat)
|
||||
|
@ -22,7 +22,9 @@
|
||||
"""
|
||||
The :mod:`openlp.core.utils` module provides the utility libraries for OpenLP.
|
||||
"""
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
@ -32,7 +34,7 @@ import urllib.request
|
||||
from http.client import HTTPException
|
||||
from random import randint
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.common import Registry, trace_error_handler
|
||||
|
||||
log = logging.getLogger(__name__ + '.__init__')
|
||||
|
||||
@ -92,7 +94,7 @@ class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler):
|
||||
return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url)
|
||||
|
||||
|
||||
def _get_user_agent():
|
||||
def get_user_agent():
|
||||
"""
|
||||
Return a user agent customised for the platform the user is on.
|
||||
"""
|
||||
@ -122,7 +124,7 @@ def get_web_page(url, header=None, update_openlp=False):
|
||||
urllib.request.install_opener(opener)
|
||||
req = urllib.request.Request(url)
|
||||
if not header or header[0].lower() != 'user-agent':
|
||||
user_agent = _get_user_agent()
|
||||
user_agent = get_user_agent()
|
||||
req.add_header('User-Agent', user_agent)
|
||||
if header:
|
||||
req.add_header(header[0], header[1])
|
||||
@ -179,4 +181,75 @@ def get_web_page(url, header=None, update_openlp=False):
|
||||
return page
|
||||
|
||||
|
||||
def get_url_file_size(url):
|
||||
"""
|
||||
Get the size of a file.
|
||||
|
||||
:param url: The URL of the file we want to download.
|
||||
"""
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
|
||||
meta = site.info()
|
||||
return int(meta.get("Content-Length"))
|
||||
except urllib.error.URLError:
|
||||
if retries > CONNECTION_RETRIES:
|
||||
raise
|
||||
else:
|
||||
retries += 1
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
|
||||
|
||||
def url_get_file(callback, url, f_path, sha256=None):
|
||||
""""
|
||||
Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
|
||||
point. Returns False on download error.
|
||||
|
||||
:param callback: the class which needs to be updated
|
||||
:param url: URL to download
|
||||
:param f_path: Destination file
|
||||
:param sha256: The check sum value to be checked against the download value
|
||||
"""
|
||||
block_count = 0
|
||||
block_size = 4096
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
filename = open(f_path, "wb")
|
||||
url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
|
||||
if sha256:
|
||||
hasher = hashlib.sha256()
|
||||
# Download until finished or canceled.
|
||||
while not callback.was_cancelled:
|
||||
data = url_file.read(block_size)
|
||||
if not data:
|
||||
break
|
||||
filename.write(data)
|
||||
if sha256:
|
||||
hasher.update(data)
|
||||
block_count += 1
|
||||
callback._download_progress(block_count, block_size)
|
||||
filename.close()
|
||||
if sha256 and hasher.hexdigest() != sha256:
|
||||
log.error('sha256 sums did not match for file: {file}'.format(file=f_path))
|
||||
os.remove(f_path)
|
||||
return False
|
||||
except (urllib.error.URLError, socket.timeout) as err:
|
||||
trace_error_handler(log)
|
||||
filename.close()
|
||||
os.remove(f_path)
|
||||
if retries > CONNECTION_RETRIES:
|
||||
return False
|
||||
else:
|
||||
retries += 1
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
break
|
||||
# Delete file if cancelled, it may be a partial file.
|
||||
if callback.was_cancelled:
|
||||
os.remove(f_path)
|
||||
return True
|
||||
|
||||
__all__ = ['get_web_page']
|
@ -216,8 +216,8 @@ class Settings(QtCore.QSettings):
|
||||
('advanced/default color', 'core/logo background color', []), # Default image renamed + moved to general > 2.4.
|
||||
('advanced/default image', 'core/logo file', []), # Default image renamed + moved to general after 2.4.
|
||||
('shortcuts/escapeItem', 'shortcuts/desktopScreenEnable', []), # Escape item was removed in 2.6.
|
||||
('shortcuts/offlineHelpItem', 'shortcuts/HelpItem', []), # Online and Offline help were combined in 2.6.
|
||||
('shortcuts/onlineHelpItem', 'shortcuts/HelpItem', []) # Online and Offline help were combined in 2.6.
|
||||
('shortcuts/offlineHelpItem', 'shortcuts/userManualItem', []), # Online and Offline help were combined in 2.6.
|
||||
('shortcuts/onlineHelpItem', 'shortcuts/userManualItem', []) # Online and Offline help were combined in 2.6.
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@ -276,7 +276,7 @@ class Settings(QtCore.QSettings):
|
||||
'shortcuts/fileSaveItem': [QtGui.QKeySequence(QtGui.QKeySequence.Save)],
|
||||
'shortcuts/fileOpenItem': [QtGui.QKeySequence(QtGui.QKeySequence.Open)],
|
||||
'shortcuts/goLive': [],
|
||||
'shortcuts/HelpItem': [QtGui.QKeySequence(QtGui.QKeySequence.HelpContents)],
|
||||
'shortcuts/userManualItem': [QtGui.QKeySequence(QtGui.QKeySequence.HelpContents)],
|
||||
'shortcuts/importThemeItem': [],
|
||||
'shortcuts/importBibleItem': [],
|
||||
'shortcuts/listViewBiblesDeleteItem': [QtGui.QKeySequence(QtGui.QKeySequence.Delete)],
|
||||
|
@ -41,6 +41,7 @@ class UiAboutDialog(object):
|
||||
about_dialog.setObjectName('about_dialog')
|
||||
about_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
|
||||
self.about_dialog_layout = QtWidgets.QVBoxLayout(about_dialog)
|
||||
self.about_dialog_layout.setContentsMargins(8, 8, 8, 8)
|
||||
self.about_dialog_layout.setObjectName('about_dialog_layout')
|
||||
self.logo_label = QtWidgets.QLabel(about_dialog)
|
||||
self.logo_label.setPixmap(QtGui.QPixmap(':/graphics/openlp-about-logo.png'))
|
||||
|
@ -22,7 +22,6 @@
|
||||
"""
|
||||
This module contains the first time wizard.
|
||||
"""
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
@ -39,7 +38,7 @@ from openlp.core.common import Registry, RegistryProperties, AppLocation, Settin
|
||||
translate, clean_button_text, trace_error_handler
|
||||
from openlp.core.lib import PluginStatus, build_icon
|
||||
from openlp.core.lib.ui import critical_error_message_box
|
||||
from openlp.core.lib.webpagereader import get_web_page, CONNECTION_RETRIES, CONNECTION_TIMEOUT
|
||||
from openlp.core.common.httputils import get_web_page, get_url_file_size, url_get_file, CONNECTION_TIMEOUT
|
||||
from .firsttimewizard import UiFirstTimeWizard, FirstTimePage
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -395,54 +394,6 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
self.was_cancelled = True
|
||||
self.close()
|
||||
|
||||
def url_get_file(self, url, f_path, sha256=None):
|
||||
""""
|
||||
Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
|
||||
point. Returns False on download error.
|
||||
|
||||
:param url: URL to download
|
||||
:param f_path: Destination file
|
||||
"""
|
||||
block_count = 0
|
||||
block_size = 4096
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
filename = open(f_path, "wb")
|
||||
url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
|
||||
if sha256:
|
||||
hasher = hashlib.sha256()
|
||||
# Download until finished or canceled.
|
||||
while not self.was_cancelled:
|
||||
data = url_file.read(block_size)
|
||||
if not data:
|
||||
break
|
||||
filename.write(data)
|
||||
if sha256:
|
||||
hasher.update(data)
|
||||
block_count += 1
|
||||
self._download_progress(block_count, block_size)
|
||||
filename.close()
|
||||
if sha256 and hasher.hexdigest() != sha256:
|
||||
log.error('sha256 sums did not match for file: {file}'.format(file=f_path))
|
||||
os.remove(f_path)
|
||||
return False
|
||||
except (urllib.error.URLError, socket.timeout) as err:
|
||||
trace_error_handler(log)
|
||||
filename.close()
|
||||
os.remove(f_path)
|
||||
if retries > CONNECTION_RETRIES:
|
||||
return False
|
||||
else:
|
||||
retries += 1
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
break
|
||||
# Delete file if cancelled, it may be a partial file.
|
||||
if self.was_cancelled:
|
||||
os.remove(f_path)
|
||||
return True
|
||||
|
||||
def _build_theme_screenshots(self):
|
||||
"""
|
||||
This method builds the theme screenshots' icons for all items in the ``self.themes_list_widget``.
|
||||
@ -455,26 +406,6 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
if item:
|
||||
item.setIcon(build_icon(os.path.join(gettempdir(), 'openlp', screenshot)))
|
||||
|
||||
def _get_file_size(self, url):
|
||||
"""
|
||||
Get the size of a file.
|
||||
|
||||
:param url: The URL of the file we want to download.
|
||||
"""
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
|
||||
meta = site.info()
|
||||
return int(meta.get("Content-Length"))
|
||||
except urllib.error.URLError:
|
||||
if retries > CONNECTION_RETRIES:
|
||||
raise
|
||||
else:
|
||||
retries += 1
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
|
||||
def _download_progress(self, count, block_size):
|
||||
"""
|
||||
Calculate and display the download progress.
|
||||
@ -510,7 +441,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
item = self.songs_list_widget.item(i)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
filename, sha256 = item.data(QtCore.Qt.UserRole)
|
||||
size = self._get_file_size('{path}{name}'.format(path=self.songs_url, name=filename))
|
||||
size = get_url_file_size('{path}{name}'.format(path=self.songs_url, name=filename))
|
||||
self.max_progress += size
|
||||
# Loop through the Bibles list and increase for each selected item
|
||||
iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget)
|
||||
@ -519,7 +450,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
item = iterator.value()
|
||||
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
|
||||
filename, sha256 = item.data(0, QtCore.Qt.UserRole)
|
||||
size = self._get_file_size('{path}{name}'.format(path=self.bibles_url, name=filename))
|
||||
size = get_url_file_size('{path}{name}'.format(path=self.bibles_url, name=filename))
|
||||
self.max_progress += size
|
||||
iterator += 1
|
||||
# Loop through the themes list and increase for each selected item
|
||||
@ -528,7 +459,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
item = self.themes_list_widget.item(i)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
filename, sha256 = item.data(QtCore.Qt.UserRole)
|
||||
size = self._get_file_size('{path}{name}'.format(path=self.themes_url, name=filename))
|
||||
size = get_url_file_size('{path}{name}'.format(path=self.themes_url, name=filename))
|
||||
self.max_progress += size
|
||||
except urllib.error.URLError:
|
||||
trace_error_handler(log)
|
||||
@ -636,8 +567,8 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
self._increment_progress_bar(self.downloading.format(name=filename), 0)
|
||||
self.previous_size = 0
|
||||
destination = os.path.join(songs_destination, str(filename))
|
||||
if not self.url_get_file('{path}{name}'.format(path=self.songs_url, name=filename),
|
||||
destination, sha256):
|
||||
if not url_get_file(self, '{path}{name}'.format(path=self.songs_url, name=filename),
|
||||
destination, sha256):
|
||||
missed_files.append('Song: {name}'.format(name=filename))
|
||||
# Download Bibles
|
||||
bibles_iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget)
|
||||
@ -648,9 +579,9 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
# TODO: Tested at home
|
||||
self._increment_progress_bar(self.downloading.format(name=bible), 0)
|
||||
self.previous_size = 0
|
||||
if not self.url_get_file('{path}{name}'.format(path=self.bibles_url, name=bible),
|
||||
os.path.join(bibles_destination, bible),
|
||||
sha256):
|
||||
if not url_get_file(self, '{path}{name}'.format(path=self.bibles_url, name=bible),
|
||||
os.path.join(bibles_destination, bible),
|
||||
sha256):
|
||||
missed_files.append('Bible: {name}'.format(name=bible))
|
||||
bibles_iterator += 1
|
||||
# Download themes
|
||||
@ -661,9 +592,9 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
# TODO: Tested at home
|
||||
self._increment_progress_bar(self.downloading.format(name=theme), 0)
|
||||
self.previous_size = 0
|
||||
if not self.url_get_file('{path}{name}'.format(path=self.themes_url, name=theme),
|
||||
os.path.join(themes_destination, theme),
|
||||
sha256):
|
||||
if not url_get_file(self, '{path}{name}'.format(path=self.themes_url, name=theme),
|
||||
os.path.join(themes_destination, theme),
|
||||
sha256):
|
||||
missed_files.append('Theme: {name}'.format(name=theme))
|
||||
if missed_files:
|
||||
file_list = ''
|
||||
|
@ -54,7 +54,7 @@ class MediaDockManager(object):
|
||||
match = True
|
||||
break
|
||||
if not match:
|
||||
self.media_dock.addItem(media_item, visible_title['title'])
|
||||
self.media_dock.addItem(media_item, media_item.plugin.icon, visible_title['title'])
|
||||
|
||||
def remove_dock(self, media_item):
|
||||
"""
|
||||
|
@ -46,6 +46,7 @@ class WizardStrings(object):
|
||||
OSIS = 'OSIS'
|
||||
ZEF = 'Zefania'
|
||||
SWORD = 'Sword'
|
||||
WordProject = 'WordProject'
|
||||
# These strings should need a good reason to be retranslated elsewhere.
|
||||
FinishedImport = translate('OpenLP.Ui', 'Finished import.')
|
||||
FormatLabel = translate('OpenLP.Ui', 'Format:')
|
||||
@ -95,6 +96,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
|
||||
super(OpenLPWizard, self).__init__(parent)
|
||||
self.plugin = plugin
|
||||
self.with_progress_page = add_progress_page
|
||||
self.setFixedWidth(640)
|
||||
self.setObjectName(name)
|
||||
self.open_icon = build_icon(':/general/general_open.png')
|
||||
self.delete_icon = build_icon(':/general/general_delete.png')
|
||||
|
@ -52,21 +52,17 @@ from openlp.core.ui.lib.mediadockmanager import MediaDockManager
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
MEDIA_MANAGER_STYLE = """
|
||||
QToolBox {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
QToolBox::tab {
|
||||
::tab#media_tool_box {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
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: 1.0 palette(button));
|
||||
border: 1px solid palette(mid);
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
/* This is here to make the tabs on KDE with the Breeze theme work */
|
||||
::tab:selected {}
|
||||
"""
|
||||
|
||||
PROGRESSBAR_STYLE = """
|
||||
@ -312,10 +308,9 @@ class Ui_MainWindow(object):
|
||||
elif is_macosx():
|
||||
self.local_help_file = os.path.join(AppLocation.get_directory(AppLocation.AppDir),
|
||||
'..', 'Resources', 'OpenLP.help')
|
||||
self.on_help_item = create_action(main_window, 'HelpItem',
|
||||
icon=':/system/system_help_contents.png',
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().Help, triggers=self.on_help_clicked)
|
||||
self.user_manual_item = create_action(main_window, 'userManualItem', icon=':/system/system_help_contents.png',
|
||||
can_shortcuts=True, category=UiStrings().Help,
|
||||
triggers=self.on_help_clicked)
|
||||
self.web_site_item = create_action(main_window, 'webSiteItem', can_shortcuts=True, category=UiStrings().Help)
|
||||
# Shortcuts not connected to buttons or menu entries.
|
||||
self.search_shortcut_action = create_action(main_window,
|
||||
@ -354,7 +349,7 @@ class Ui_MainWindow(object):
|
||||
add_actions(self.tools_menu, (self.tools_open_data_folder, None))
|
||||
add_actions(self.tools_menu, (self.tools_first_time_wizard, None))
|
||||
add_actions(self.tools_menu, [self.update_theme_images])
|
||||
add_actions(self.help_menu, (self.on_help_item, None, self.web_site_item, self.about_item))
|
||||
add_actions(self.help_menu, (self.user_manual_item, None, self.web_site_item, self.about_item))
|
||||
add_actions(self.menu_bar, (self.file_menu.menuAction(), self.view_menu.menuAction(),
|
||||
self.tools_menu.menuAction(), self.settings_menu.menuAction(), self.help_menu.menuAction()))
|
||||
add_actions(self, [self.search_shortcut_action])
|
||||
@ -450,7 +445,7 @@ class Ui_MainWindow(object):
|
||||
'from here.'))
|
||||
self.about_item.setText(translate('OpenLP.MainWindow', '&About'))
|
||||
self.about_item.setStatusTip(translate('OpenLP.MainWindow', 'More information about OpenLP.'))
|
||||
self.on_help_item.setText(translate('OpenLP.MainWindow', '&User Manual'))
|
||||
self.user_manual_item.setText(translate('OpenLP.MainWindow', '&User Manual'))
|
||||
self.search_shortcut_action.setText(UiStrings().Search)
|
||||
self.search_shortcut_action.setToolTip(
|
||||
translate('OpenLP.MainWindow', 'Jump to the search box of the current active plugin.'))
|
||||
|
@ -243,7 +243,7 @@ class SourceSelectTabs(QtWidgets.QDialog):
|
||||
title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
|
||||
self.setWindowTitle(title)
|
||||
self.setObjectName('source_select_tabs')
|
||||
self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
|
||||
self.setWindowIcon(build_icon(':/icon/openlp-log.svg'))
|
||||
self.setModal(True)
|
||||
self.layout = QtWidgets.QVBoxLayout()
|
||||
self.layout.setObjectName('source_select_tabs_layout')
|
||||
@ -395,7 +395,7 @@ class SourceSelectSingle(QtWidgets.QDialog):
|
||||
else:
|
||||
title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
|
||||
self.setObjectName('source_select_single')
|
||||
self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
|
||||
self.setWindowIcon(build_icon(':/icon/openlp-log.svg'))
|
||||
self.setModal(True)
|
||||
self.edit = edit
|
||||
|
||||
|
@ -44,9 +44,9 @@ class Ui_ThemeWizard(object):
|
||||
theme_wizard.setModal(True)
|
||||
theme_wizard.setOptions(QtWidgets.QWizard.IndependentPages |
|
||||
QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.HaveCustomButton1)
|
||||
theme_wizard.setFixedWidth(640)
|
||||
if is_macosx():
|
||||
theme_wizard.setPixmap(QtWidgets.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
|
||||
theme_wizard.resize(646, 400)
|
||||
else:
|
||||
theme_wizard.setWizardStyle(QtWidgets.QWizard.ModernStyle)
|
||||
self.spacer = QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
|
||||
|
@ -125,6 +125,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.csv_verses_button.clicked.connect(self.on_csv_verses_browse_button_clicked)
|
||||
self.open_song_browse_button.clicked.connect(self.on_open_song_browse_button_clicked)
|
||||
self.zefania_browse_button.clicked.connect(self.on_zefania_browse_button_clicked)
|
||||
self.wordproject_browse_button.clicked.connect(self.on_wordproject_browse_button_clicked)
|
||||
self.web_update_button.clicked.connect(self.on_web_update_button_clicked)
|
||||
self.sword_browse_button.clicked.connect(self.on_sword_browse_button_clicked)
|
||||
self.sword_zipbrowse_button.clicked.connect(self.on_sword_zipbrowse_button_clicked)
|
||||
@ -143,7 +144,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.format_label = QtWidgets.QLabel(self.select_page)
|
||||
self.format_label.setObjectName('FormatLabel')
|
||||
self.format_combo_box = QtWidgets.QComboBox(self.select_page)
|
||||
self.format_combo_box.addItems(['', '', '', '', '', ''])
|
||||
self.format_combo_box.addItems(['', '', '', '', '', '', ''])
|
||||
self.format_combo_box.setObjectName('FormatComboBox')
|
||||
self.format_layout.addRow(self.format_label, self.format_combo_box)
|
||||
self.spacer = QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
|
||||
@ -161,6 +162,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.osis_file_layout = QtWidgets.QHBoxLayout()
|
||||
self.osis_file_layout.setObjectName('OsisFileLayout')
|
||||
self.osis_file_edit = QtWidgets.QLineEdit(self.osis_widget)
|
||||
self.osis_file_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.osis_file_edit.setObjectName('OsisFileEdit')
|
||||
self.osis_file_layout.addWidget(self.osis_file_edit)
|
||||
self.osis_browse_button = QtWidgets.QToolButton(self.osis_widget)
|
||||
@ -180,6 +182,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.csv_books_layout = QtWidgets.QHBoxLayout()
|
||||
self.csv_books_layout.setObjectName('CsvBooksLayout')
|
||||
self.csv_books_edit = QtWidgets.QLineEdit(self.csv_widget)
|
||||
self.csv_books_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.csv_books_edit.setObjectName('CsvBooksEdit')
|
||||
self.csv_books_layout.addWidget(self.csv_books_edit)
|
||||
self.csv_books_button = QtWidgets.QToolButton(self.csv_widget)
|
||||
@ -192,6 +195,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.csv_verses_layout = QtWidgets.QHBoxLayout()
|
||||
self.csv_verses_layout.setObjectName('CsvVersesLayout')
|
||||
self.csv_verses_edit = QtWidgets.QLineEdit(self.csv_widget)
|
||||
self.csv_verses_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.csv_verses_edit.setObjectName('CsvVersesEdit')
|
||||
self.csv_verses_layout.addWidget(self.csv_verses_edit)
|
||||
self.csv_verses_button = QtWidgets.QToolButton(self.csv_widget)
|
||||
@ -211,6 +215,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.open_song_file_layout = QtWidgets.QHBoxLayout()
|
||||
self.open_song_file_layout.setObjectName('OpenSongFileLayout')
|
||||
self.open_song_file_edit = QtWidgets.QLineEdit(self.open_song_widget)
|
||||
self.open_song_file_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.open_song_file_edit.setObjectName('OpenSongFileEdit')
|
||||
self.open_song_file_layout.addWidget(self.open_song_file_edit)
|
||||
self.open_song_browse_button = QtWidgets.QToolButton(self.open_song_widget)
|
||||
@ -300,61 +305,84 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.sword_widget = QtWidgets.QWidget(self.select_page)
|
||||
self.sword_widget.setObjectName('SwordWidget')
|
||||
self.sword_layout = QtWidgets.QVBoxLayout(self.sword_widget)
|
||||
self.sword_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.sword_layout.setObjectName('SwordLayout')
|
||||
self.sword_tab_widget = QtWidgets.QTabWidget(self.sword_widget)
|
||||
self.sword_tab_widget.setObjectName('SwordTabWidget')
|
||||
self.sword_folder_tab = QtWidgets.QWidget(self.sword_tab_widget)
|
||||
self.sword_folder_tab.setObjectName('SwordFolderTab')
|
||||
self.sword_folder_tab_layout = QtWidgets.QGridLayout(self.sword_folder_tab)
|
||||
self.sword_folder_tab_layout = QtWidgets.QFormLayout(self.sword_folder_tab)
|
||||
self.sword_folder_tab_layout.setObjectName('SwordTabFolderLayout')
|
||||
self.sword_folder_label = QtWidgets.QLabel(self.sword_folder_tab)
|
||||
self.sword_folder_label.setObjectName('SwordSourceLabel')
|
||||
self.sword_folder_tab_layout.addWidget(self.sword_folder_label, 0, 0)
|
||||
self.sword_folder_label.setObjectName('SwordFolderLabel')
|
||||
self.sword_folder_edit = QtWidgets.QLineEdit(self.sword_folder_tab)
|
||||
self.sword_folder_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.sword_folder_edit.setObjectName('SwordFolderEdit')
|
||||
self.sword_browse_button = QtWidgets.QToolButton(self.sword_folder_tab)
|
||||
self.sword_browse_button.setIcon(self.open_icon)
|
||||
self.sword_browse_button.setObjectName('SwordBrowseButton')
|
||||
self.sword_folder_tab_layout.addWidget(self.sword_folder_edit, 0, 1)
|
||||
self.sword_folder_tab_layout.addWidget(self.sword_browse_button, 0, 2)
|
||||
self.sword_folder_layout = QtWidgets.QHBoxLayout()
|
||||
self.sword_folder_layout.addWidget(self.sword_folder_edit)
|
||||
self.sword_folder_layout.addWidget(self.sword_browse_button)
|
||||
self.sword_folder_tab_layout.addRow(self.sword_folder_label, self.sword_folder_layout)
|
||||
self.sword_bible_label = QtWidgets.QLabel(self.sword_folder_tab)
|
||||
self.sword_bible_label.setObjectName('SwordBibleLabel')
|
||||
self.sword_folder_tab_layout.addWidget(self.sword_bible_label, 1, 0)
|
||||
self.sword_bible_combo_box = QtWidgets.QComboBox(self.sword_folder_tab)
|
||||
self.sword_bible_combo_box.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
self.sword_bible_combo_box.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically)
|
||||
self.sword_bible_combo_box.setObjectName('SwordBibleComboBox')
|
||||
self.sword_folder_tab_layout.addWidget(self.sword_bible_combo_box, 1, 1)
|
||||
self.sword_folder_tab_layout.addRow(self.sword_bible_label, self.sword_bible_combo_box)
|
||||
self.sword_tab_widget.addTab(self.sword_folder_tab, '')
|
||||
self.sword_zip_tab = QtWidgets.QWidget(self.sword_tab_widget)
|
||||
self.sword_zip_tab.setObjectName('SwordZipTab')
|
||||
self.sword_zip_layout = QtWidgets.QGridLayout(self.sword_zip_tab)
|
||||
self.sword_zip_layout = QtWidgets.QFormLayout(self.sword_zip_tab)
|
||||
self.sword_zip_layout.setObjectName('SwordZipLayout')
|
||||
self.sword_zipfile_label = QtWidgets.QLabel(self.sword_zip_tab)
|
||||
self.sword_zipfile_label.setObjectName('SwordZipFileLabel')
|
||||
self.sword_zipfile_edit = QtWidgets.QLineEdit(self.sword_zip_tab)
|
||||
self.sword_zipfile_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.sword_zipfile_edit.setObjectName('SwordZipFileEdit')
|
||||
self.sword_zipbrowse_button = QtWidgets.QToolButton(self.sword_zip_tab)
|
||||
self.sword_zipbrowse_button.setIcon(self.open_icon)
|
||||
self.sword_zipbrowse_button.setObjectName('SwordZipBrowseButton')
|
||||
self.sword_zipfile_layout = QtWidgets.QHBoxLayout()
|
||||
self.sword_zipfile_layout.addWidget(self.sword_zipfile_edit)
|
||||
self.sword_zipfile_layout.addWidget(self.sword_zipbrowse_button)
|
||||
self.sword_zip_layout.addRow(self.sword_zipfile_label, self.sword_zipfile_layout)
|
||||
self.sword_zipbible_label = QtWidgets.QLabel(self.sword_folder_tab)
|
||||
self.sword_zipbible_label.setObjectName('SwordZipBibleLabel')
|
||||
self.sword_zipbible_combo_box = QtWidgets.QComboBox(self.sword_zip_tab)
|
||||
self.sword_zipbible_combo_box.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
self.sword_zipbible_combo_box.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically)
|
||||
self.sword_zipbible_combo_box.setObjectName('SwordZipBibleComboBox')
|
||||
self.sword_zip_layout.addWidget(self.sword_zipfile_label, 0, 0)
|
||||
self.sword_zip_layout.addWidget(self.sword_zipfile_edit, 0, 1)
|
||||
self.sword_zip_layout.addWidget(self.sword_zipbrowse_button, 0, 2)
|
||||
self.sword_zip_layout.addWidget(self.sword_zipbible_label, 1, 0)
|
||||
self.sword_zip_layout.addWidget(self.sword_zipbible_combo_box, 1, 1)
|
||||
self.sword_zip_layout.addRow(self.sword_zipbible_label, self.sword_zipbible_combo_box)
|
||||
self.sword_tab_widget.addTab(self.sword_zip_tab, '')
|
||||
self.sword_layout.addWidget(self.sword_tab_widget)
|
||||
self.sword_disabled_label = QtWidgets.QLabel(self.sword_widget)
|
||||
self.sword_disabled_label.setObjectName('SwordDisabledLabel')
|
||||
self.sword_layout.addWidget(self.sword_disabled_label)
|
||||
self.select_stack.addWidget(self.sword_widget)
|
||||
self.wordproject_widget = QtWidgets.QWidget(self.select_page)
|
||||
self.wordproject_widget.setObjectName('WordProjectWidget')
|
||||
self.wordproject_layout = QtWidgets.QFormLayout(self.wordproject_widget)
|
||||
self.wordproject_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.wordproject_layout.setObjectName('WordProjectLayout')
|
||||
self.wordproject_file_label = QtWidgets.QLabel(self.wordproject_widget)
|
||||
self.wordproject_file_label.setObjectName('WordProjectFileLabel')
|
||||
self.wordproject_file_layout = QtWidgets.QHBoxLayout()
|
||||
self.wordproject_file_layout.setObjectName('WordProjectFileLayout')
|
||||
self.wordproject_file_edit = QtWidgets.QLineEdit(self.wordproject_widget)
|
||||
self.wordproject_file_edit.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
|
||||
self.wordproject_file_edit.setObjectName('WordProjectFileEdit')
|
||||
self.wordproject_file_layout.addWidget(self.wordproject_file_edit)
|
||||
self.wordproject_browse_button = QtWidgets.QToolButton(self.wordproject_widget)
|
||||
self.wordproject_browse_button.setIcon(self.open_icon)
|
||||
self.wordproject_browse_button.setObjectName('WordProjectBrowseButton')
|
||||
self.wordproject_file_layout.addWidget(self.wordproject_browse_button)
|
||||
self.wordproject_layout.addRow(self.wordproject_file_label, self.wordproject_file_layout)
|
||||
self.wordproject_layout.setItem(5, QtWidgets.QFormLayout.LabelRole, self.spacer)
|
||||
self.select_stack.addWidget(self.wordproject_widget)
|
||||
self.select_page_layout.addLayout(self.select_stack)
|
||||
self.addPage(self.select_page)
|
||||
# License Page
|
||||
@ -406,6 +434,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.format_combo_box.setItemText(BibleFormat.OSIS, WizardStrings.OSIS)
|
||||
self.format_combo_box.setItemText(BibleFormat.CSV, WizardStrings.CSV)
|
||||
self.format_combo_box.setItemText(BibleFormat.OpenSong, WizardStrings.OS)
|
||||
self.format_combo_box.setItemText(BibleFormat.WordProject, WizardStrings.WordProject)
|
||||
self.format_combo_box.setItemText(BibleFormat.WebDownload, translate('BiblesPlugin.ImportWizardForm',
|
||||
'Web Download'))
|
||||
self.format_combo_box.setItemText(BibleFormat.Zefania, WizardStrings.ZEF)
|
||||
@ -416,6 +445,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.open_song_file_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
|
||||
self.web_source_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Location:'))
|
||||
self.zefania_file_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
|
||||
self.wordproject_file_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
|
||||
self.web_update_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Click to download bible list'))
|
||||
self.web_update_button.setText(translate('BiblesPlugin.ImportWizardForm', 'Download bible list'))
|
||||
self.web_source_combo_box.setItemText(WebDownload.Crosswalk, translate('BiblesPlugin.ImportWizardForm',
|
||||
@ -475,6 +505,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
"""
|
||||
Validate the current page before moving on to the next page.
|
||||
"""
|
||||
log.debug(self.size())
|
||||
if self.currentPage() == self.welcome_page:
|
||||
return True
|
||||
elif self.currentPage() == self.select_page:
|
||||
@ -512,6 +543,12 @@ class BibleImportForm(OpenLPWizard):
|
||||
critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % WizardStrings.ZEF)
|
||||
self.zefania_file_edit.setFocus()
|
||||
return False
|
||||
elif self.field('source_format') == BibleFormat.WordProject:
|
||||
if not self.field('wordproject_file'):
|
||||
critical_error_message_box(UiStrings().NFSs,
|
||||
WizardStrings.YouSpecifyFile % WizardStrings.WordProject)
|
||||
self.wordproject_file_edit.setFocus()
|
||||
return False
|
||||
elif self.field('source_format') == BibleFormat.WebDownload:
|
||||
# If count is 0 the bible list has not yet been downloaded
|
||||
if self.web_translation_combo_box.count() == 0:
|
||||
@ -635,6 +672,14 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.ZEF, self.zefania_file_edit,
|
||||
'last directory import')
|
||||
|
||||
def on_wordproject_browse_button_clicked(self):
|
||||
"""
|
||||
Show the file open dialog for the WordProject file.
|
||||
"""
|
||||
# TODO: Verify format() with variable template
|
||||
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.WordProject, self.wordproject_file_edit,
|
||||
'last directory import')
|
||||
|
||||
def on_web_update_button_clicked(self):
|
||||
"""
|
||||
Download list of bibles from Crosswalk, BibleServer and BibleGateway.
|
||||
@ -715,6 +760,7 @@ class BibleImportForm(OpenLPWizard):
|
||||
self.select_page.registerField('csv_versefile', self.csv_verses_edit)
|
||||
self.select_page.registerField('opensong_file', self.open_song_file_edit)
|
||||
self.select_page.registerField('zefania_file', self.zefania_file_edit)
|
||||
self.select_page.registerField('wordproject_file', self.wordproject_file_edit)
|
||||
self.select_page.registerField('web_location', self.web_source_combo_box)
|
||||
self.select_page.registerField('web_biblename', self.web_translation_combo_box)
|
||||
self.select_page.registerField('sword_folder_path', self.sword_folder_edit)
|
||||
@ -814,6 +860,10 @@ class BibleImportForm(OpenLPWizard):
|
||||
# Import a Zefania bible.
|
||||
importer = self.manager.import_bible(BibleFormat.Zefania, name=license_version,
|
||||
filename=self.field('zefania_file'))
|
||||
elif bible_type == BibleFormat.WordProject:
|
||||
# Import a WordProject bible.
|
||||
importer = self.manager.import_bible(BibleFormat.WordProject, name=license_version,
|
||||
filename=self.field('wordproject_file'))
|
||||
elif bible_type == BibleFormat.SWORD:
|
||||
# Import a SWORD bible.
|
||||
if self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_folder_tab):
|
||||
|
@ -32,7 +32,7 @@ from bs4 import BeautifulSoup, NavigableString, Tag
|
||||
|
||||
from openlp.core.common import Registry, RegistryProperties, translate
|
||||
from openlp.core.lib.ui import critical_error_message_box
|
||||
from openlp.core.lib.webpagereader import get_web_page
|
||||
from openlp.core.common.httputils import get_web_page
|
||||
from openlp.plugins.bibles.lib import SearchResults
|
||||
from openlp.plugins.bibles.lib.bibleimport import BibleImport
|
||||
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, Book
|
||||
|
169
openlp/plugins/bibles/lib/importers/wordproject.py
Normal file
169
openlp/plugins/bibles/lib/importers/wordproject.py
Normal file
@ -0,0 +1,169 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
from codecs import open as copen
|
||||
from tempfile import TemporaryDirectory
|
||||
from zipfile import ZipFile
|
||||
|
||||
from bs4 import BeautifulSoup, Tag, NavigableString
|
||||
|
||||
from openlp.plugins.bibles.lib.bibleimport import BibleImport
|
||||
|
||||
BOOK_NUMBER_PATTERN = re.compile(r'\[(\d+)\]')
|
||||
REPLACE_SPACES = re.compile(r'\s{2,}')
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WordProjectBible(BibleImport):
|
||||
"""
|
||||
`WordProject <http://www.wordproaudio.com/>`_ Bible format importer class.
|
||||
"""
|
||||
def _cleanup(self):
|
||||
"""
|
||||
Clean up after ourselves
|
||||
"""
|
||||
self.tmp.cleanup()
|
||||
|
||||
def _unzip_file(self):
|
||||
"""
|
||||
Unzip the file to a temporary directory
|
||||
"""
|
||||
self.tmp = TemporaryDirectory()
|
||||
zip_file = ZipFile(os.path.abspath(self.filename))
|
||||
zip_file.extractall(self.tmp.name)
|
||||
self.base_dir = os.path.join(self.tmp.name, os.path.splitext(os.path.basename(self.filename))[0])
|
||||
|
||||
def process_books(self):
|
||||
"""
|
||||
Extract and create the bible books from the parsed html
|
||||
|
||||
:param bible_data: parsed xml
|
||||
:return: None
|
||||
"""
|
||||
with copen(os.path.join(self.base_dir, 'index.htm'), encoding='utf-8', errors='ignore') as index_file:
|
||||
page = index_file.read()
|
||||
soup = BeautifulSoup(page, 'lxml')
|
||||
bible_books = soup.find('div', 'textOptions').find_all('li')
|
||||
book_count = len(bible_books)
|
||||
for li_book in bible_books:
|
||||
log.debug(li_book)
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
# Sometimes the structure is "[1] <a>Genesis</a>", and sometimes it's "<a>[1] Genesis</a>"
|
||||
if isinstance(li_book.contents[0], NavigableString) and str(li_book.contents[0]).strip():
|
||||
book_string = str(li_book.contents[0])
|
||||
book_name = str(li_book.a.contents[0])
|
||||
elif li_book.a:
|
||||
book_string, book_name = str(li_book.a.contents[0]).split(' ', 1)
|
||||
book_link = li_book.a['href']
|
||||
book_id = int(BOOK_NUMBER_PATTERN.search(book_string).group(1))
|
||||
book_name = book_name.strip()
|
||||
db_book = self.find_and_create_book(book_name, book_count, self.language_id, book_id)
|
||||
self.process_chapters(db_book, book_id, book_link)
|
||||
self.session.commit()
|
||||
|
||||
def process_chapters(self, db_book, book_id, book_link):
|
||||
"""
|
||||
Extract the chapters, and do some initial processing of the verses
|
||||
|
||||
:param book: An OpenLP bible database book object
|
||||
:param chapters: parsed chapters
|
||||
:return: None
|
||||
"""
|
||||
log.debug(book_link)
|
||||
book_file = os.path.join(self.base_dir, os.path.normpath(book_link))
|
||||
with copen(book_file, encoding='utf-8', errors='ignore') as f:
|
||||
page = f.read()
|
||||
soup = BeautifulSoup(page, 'lxml')
|
||||
header_div = soup.find('div', 'textHeader')
|
||||
chapters_p = header_div.find('p')
|
||||
if not chapters_p:
|
||||
chapters_p = soup.p
|
||||
log.debug(chapters_p)
|
||||
for item in chapters_p.contents:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
if isinstance(item, Tag) and item.name in ['a', 'span']:
|
||||
chapter_number = int(item.string.strip())
|
||||
self.set_current_chapter(db_book.name, chapter_number)
|
||||
self.process_verses(db_book, book_id, chapter_number)
|
||||
|
||||
def process_verses(self, db_book, book_number, chapter_number):
|
||||
"""
|
||||
Get the verses for a particular book
|
||||
"""
|
||||
chapter_file_name = os.path.join(self.base_dir, '{:02d}'.format(book_number), '{}.htm'.format(chapter_number))
|
||||
with copen(chapter_file_name, encoding='utf-8', errors='ignore') as chapter_file:
|
||||
page = chapter_file.read()
|
||||
soup = BeautifulSoup(page, 'lxml')
|
||||
text_body = soup.find('div', 'textBody')
|
||||
if text_body:
|
||||
verses_p = text_body.find('p')
|
||||
else:
|
||||
verses_p = soup.find_all('p')[2]
|
||||
verse_number = 0
|
||||
verse_text = ''
|
||||
for item in verses_p.contents:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
if isinstance(item, Tag) and 'verse' in item.get('class', []):
|
||||
if verse_number > 0:
|
||||
self.process_verse(db_book, chapter_number, verse_number, verse_text.strip())
|
||||
verse_number = int(item.string.strip())
|
||||
verse_text = ''
|
||||
elif isinstance(item, NavigableString):
|
||||
verse_text += str(item)
|
||||
elif isinstance(item, Tag) and item.name in ['span', 'a']:
|
||||
verse_text += str(item.string)
|
||||
else:
|
||||
log.warning('Can\'t store %s', item)
|
||||
self.process_verse(db_book, chapter_number, verse_number, verse_text.strip())
|
||||
|
||||
def process_verse(self, db_book, chapter_number, verse_number, verse_text):
|
||||
"""
|
||||
Process a verse element
|
||||
:param book: A database Book object
|
||||
:param chapter_number: The chapter number to add the verses to (int)
|
||||
:param element: The verse element to process. (etree element type)
|
||||
:param use_milestones: set to True to process a 'milestone' verse. Defaults to False
|
||||
:return: None
|
||||
"""
|
||||
if verse_text:
|
||||
log.debug('%s %s:%s %s', db_book.name, chapter_number, verse_number, verse_text.strip())
|
||||
self.create_verse(db_book.id, chapter_number, verse_number, verse_text.strip())
|
||||
|
||||
def do_import(self, bible_name=None):
|
||||
"""
|
||||
Loads a Bible from file.
|
||||
"""
|
||||
self.log_debug('Starting WordProject import from "{name}"'.format(name=self.filename))
|
||||
self._unzip_file()
|
||||
self.language_id = self.get_language_id(None, bible_name=self.filename)
|
||||
result = False
|
||||
if self.language_id:
|
||||
self.process_books()
|
||||
result = True
|
||||
self._cleanup()
|
||||
return result
|
@ -31,6 +31,7 @@ from .importers.http import HTTPBible
|
||||
from .importers.opensong import OpenSongBible
|
||||
from .importers.osis import OSISBible
|
||||
from .importers.zefania import ZefaniaBible
|
||||
from .importers.wordproject import WordProjectBible
|
||||
try:
|
||||
from .importers.sword import SwordBible
|
||||
except:
|
||||
@ -50,6 +51,7 @@ class BibleFormat(object):
|
||||
WebDownload = 3
|
||||
Zefania = 4
|
||||
SWORD = 5
|
||||
WordProject = 6
|
||||
|
||||
@staticmethod
|
||||
def get_class(bible_format):
|
||||
@ -70,6 +72,8 @@ class BibleFormat(object):
|
||||
return ZefaniaBible
|
||||
elif bible_format == BibleFormat.SWORD:
|
||||
return SwordBible
|
||||
elif bible_format == BibleFormat.WordProject:
|
||||
return WordProjectBible
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -84,7 +88,8 @@ class BibleFormat(object):
|
||||
BibleFormat.OpenSong,
|
||||
BibleFormat.WebDownload,
|
||||
BibleFormat.Zefania,
|
||||
BibleFormat.SWORD
|
||||
BibleFormat.SWORD,
|
||||
BibleFormat.WordProject
|
||||
]
|
||||
|
||||
|
||||
|
@ -425,6 +425,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1)
|
||||
if verse_count == 0:
|
||||
self.advancedSearchButton.setEnabled(False)
|
||||
log.warning('Not enough chapters in %s', book_ref_id)
|
||||
critical_error_message_box(message=translate('BiblesPlugin.MediaItem', 'Bible not fully loaded.'))
|
||||
else:
|
||||
self.advancedSearchButton.setEnabled(True)
|
||||
|
@ -150,7 +150,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
||||
triggers=self.on_replace_click)
|
||||
if 'webkit' not in get_media_players()[0]:
|
||||
self.replace_action.setDisabled(True)
|
||||
self.replace_action_context.setDisabled(True)
|
||||
if hasattr(self, 'replace_action_context'):
|
||||
self.replace_action_context.setDisabled(True)
|
||||
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png',
|
||||
visible=False, triggers=self.on_reset_click)
|
||||
self.media_widget = QtWidgets.QWidget(self)
|
||||
|
@ -118,13 +118,13 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
objects = self.manager.get_all_objects(cls)
|
||||
objects.sort(key=get_key)
|
||||
combo.clear()
|
||||
combo.addItem('')
|
||||
for obj in objects:
|
||||
row = combo.count()
|
||||
combo.addItem(obj.name)
|
||||
cache.append(obj.name)
|
||||
combo.setItemData(row, obj.id)
|
||||
set_case_insensitive_completer(cache, combo)
|
||||
combo.setEditText('')
|
||||
|
||||
def _add_author_to_list(self, author, author_type):
|
||||
"""
|
||||
@ -360,7 +360,6 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
authors = self.manager.get_all_objects(Author)
|
||||
authors.sort(key=get_author_key)
|
||||
self.authors_combo_box.clear()
|
||||
self.authors_combo_box.addItem('')
|
||||
self.authors = []
|
||||
for author in authors:
|
||||
row = self.authors_combo_box.count()
|
||||
@ -368,6 +367,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
self.authors_combo_box.setItemData(row, author.id)
|
||||
self.authors.append(author.display_name)
|
||||
set_case_insensitive_completer(self.authors, self.authors_combo_box)
|
||||
self.authors_combo_box.setEditText('')
|
||||
|
||||
# Types
|
||||
self.author_types_combo_box.clear()
|
||||
@ -398,11 +398,11 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
return get_natural_key(theme)
|
||||
|
||||
self.theme_combo_box.clear()
|
||||
self.theme_combo_box.addItem('')
|
||||
self.themes = theme_list
|
||||
self.themes.sort(key=get_theme_key)
|
||||
self.theme_combo_box.addItems(theme_list)
|
||||
set_case_insensitive_completer(self.themes, self.theme_combo_box)
|
||||
self.theme_combo_box.setEditText('')
|
||||
|
||||
def load_media_files(self):
|
||||
"""
|
||||
@ -442,7 +442,6 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
self.load_songbooks()
|
||||
self.load_media_files()
|
||||
self.theme_combo_box.setEditText('')
|
||||
self.theme_combo_box.setCurrentIndex(0)
|
||||
# it's a new song to preview is not possible
|
||||
self.preview_button.setVisible(False)
|
||||
|
||||
@ -591,7 +590,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
self.manager.save_object(author)
|
||||
self._add_author_to_list(author, author_type)
|
||||
self.load_authors()
|
||||
self.authors_combo_box.setCurrentIndex(0)
|
||||
self.authors_combo_box.setEditText('')
|
||||
else:
|
||||
return
|
||||
elif item > 0:
|
||||
@ -602,7 +601,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
message=translate('SongsPlugin.EditSongForm', 'This author is already in the list.'))
|
||||
else:
|
||||
self._add_author_to_list(author, author_type)
|
||||
self.authors_combo_box.setCurrentIndex(0)
|
||||
self.authors_combo_box.setEditText('')
|
||||
else:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self, UiStrings().NISs,
|
||||
@ -666,7 +665,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
topic_item.setData(QtCore.Qt.UserRole, topic.id)
|
||||
self.topics_list_view.addItem(topic_item)
|
||||
self.load_topics()
|
||||
self.topics_combo_box.setCurrentIndex(0)
|
||||
self.topics_combo_box.setEditText('')
|
||||
else:
|
||||
return
|
||||
elif item > 0:
|
||||
@ -679,7 +678,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
topic_item = QtWidgets.QListWidgetItem(str(topic.name))
|
||||
topic_item.setData(QtCore.Qt.UserRole, topic.id)
|
||||
self.topics_list_view.addItem(topic_item)
|
||||
self.topics_combo_box.setCurrentIndex(0)
|
||||
self.topics_combo_box.setEditText('')
|
||||
else:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self, UiStrings().NISs,
|
||||
@ -709,7 +708,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
self.manager.save_object(songbook)
|
||||
self.add_songbook_entry_to_list(songbook.id, songbook.name, self.songbook_entry_edit.text())
|
||||
self.load_songbooks()
|
||||
self.songbooks_combo_box.setCurrentIndex(0)
|
||||
self.songbooks_combo_box.setEditText('')
|
||||
self.songbook_entry_edit.clear()
|
||||
else:
|
||||
return
|
||||
@ -721,7 +720,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
||||
message=translate('SongsPlugin.EditSongForm', 'This Songbook is already in the list.'))
|
||||
else:
|
||||
self.add_songbook_entry_to_list(songbook.id, songbook.name, self.songbook_entry_edit.text())
|
||||
self.songbooks_combo_box.setCurrentIndex(0)
|
||||
self.songbooks_combo_box.setEditText('')
|
||||
self.songbook_entry_edit.clear()
|
||||
else:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 22 KiB |
@ -1,143 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
style="display:inline"
|
||||
version="1.0"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="svg5740"
|
||||
height="467.39178"
|
||||
width="467.39178">
|
||||
<defs
|
||||
id="defs5742">
|
||||
<linearGradient
|
||||
id="linearGradient3208">
|
||||
<stop
|
||||
id="stop3210"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:0.25098041;" />
|
||||
<stop
|
||||
id="stop3212"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3195">
|
||||
<stop
|
||||
id="stop3197"
|
||||
offset="0"
|
||||
style="stop-color:#cdcdff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3199"
|
||||
offset="1"
|
||||
style="stop-color:#ebebff;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient6359">
|
||||
<stop
|
||||
id="stop6361"
|
||||
offset="0"
|
||||
style="stop-color:#000d26;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop6363"
|
||||
offset="1"
|
||||
style="stop-color:#507fda;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
color-interpolation-filters="sRGB"
|
||||
id="filter6926">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur6928"
|
||||
stdDeviation="3.5771872" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
y2="436.03787"
|
||||
x2="418.20981"
|
||||
y1="384.05795"
|
||||
x1="117.59262"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4053"
|
||||
xlink:href="#linearGradient3195" />
|
||||
<linearGradient
|
||||
y2="371.85938"
|
||||
x2="201.10622"
|
||||
y1="480.55844"
|
||||
x1="815.75"
|
||||
gradientTransform="matrix(0.6515729,0,0,0.6515729,-72.086668,-5.3154816)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4055"
|
||||
xlink:href="#linearGradient6359" />
|
||||
<linearGradient
|
||||
y2="104.30029"
|
||||
x2="469.44925"
|
||||
y1="276.68851"
|
||||
x1="470.25891"
|
||||
gradientTransform="matrix(0.7247086,0,0,0.7843464,-109.42065,-2.1325924)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4057"
|
||||
xlink:href="#linearGradient3208" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5745">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-11.872025,-13.171852)"
|
||||
style="display:inline"
|
||||
id="layer1" />
|
||||
<g
|
||||
transform="translate(-11.872025,-13.171852)"
|
||||
style="display:inline"
|
||||
id="layer5" />
|
||||
<g
|
||||
transform="translate(-11.872025,-13.171852)"
|
||||
style="display:inline"
|
||||
id="layer3" />
|
||||
<g
|
||||
transform="translate(-11.872025,-13.171852)"
|
||||
style="display:inline"
|
||||
id="layer2" />
|
||||
<g
|
||||
transform="translate(-11.872025,-13.171852)"
|
||||
style="display:inline"
|
||||
id="layer6">
|
||||
<g
|
||||
transform="translate(9.8817328,9.8817328)"
|
||||
id="g4018">
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline;filter:url(#filter6926)"
|
||||
id="path6903"
|
||||
d="M 833.03006,395.26932 A 357.71872,357.71872 0 0 1 475.31134,752.98804 357.71872,357.71872 0 0 1 117.59262,395.26932 357.71872,357.71872 0 0 1 475.31134,37.550598 357.71872,357.71872 0 0 1 833.03006,395.26932 Z"
|
||||
transform="matrix(0.6379835,0,0,0.6379835,-67.554612,-15.189295)" />
|
||||
<path
|
||||
transform="matrix(0.6379835,0,0,0.6379835,-67.554612,-15.189295)"
|
||||
d="M 833.03006,395.26932 A 357.71872,357.71872 0 0 1 475.31134,752.98804 357.71872,357.71872 0 0 1 117.59262,395.26932 357.71872,357.71872 0 0 1 475.31134,37.550598 357.71872,357.71872 0 0 1 833.03006,395.26932 Z"
|
||||
id="path6900"
|
||||
style="fill:#051e52;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" />
|
||||
<path
|
||||
style="fill:url(#linearGradient4053);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
|
||||
id="path6317"
|
||||
d="M 833.03006,395.26932 A 357.71872,357.71872 0 0 1 475.31134,752.98804 357.71872,357.71872 0 0 1 117.59262,395.26932 357.71872,357.71872 0 0 1 475.31134,37.550598 357.71872,357.71872 0 0 1 833.03006,395.26932 Z"
|
||||
transform="matrix(0.6317287,0,0,0.6317287,-64.581662,-12.716988)" />
|
||||
<path
|
||||
style="fill:url(#linearGradient4055);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
|
||||
d="m 235.67972,13.233984 c -35.92776,0 -69.88078,8.488655 -99.97572,23.558433 L 296.72396,165.96674 452.81639,291.19091 c 4.32451,-17.35817 6.61754,-35.51197 6.61754,-54.20272 0,-123.50655 -100.24766,-223.754205 -223.75421,-223.754206 z M 79.118968,77.210299 C 71.146114,85.023824 63.764822,93.431949 57.026574,102.35694 L 274.63156,209.66285 434.20584,288.36064 275.3035,193.86221 79.118968,77.210299 z M 24.488653,162.95322 c -3.62786,10.33827 -6.504275,21.02069 -8.592618,31.98816 L 260.17479,255.29332 422.98657,295.52794 260.21551,241.36595 24.488653,162.95322 z M 13.513722,263.49906 c 1.305042,11.03747 3.397359,21.8274 6.251027,32.31395 l 228.539191,6.51573 173.46093,4.96824 L 253.55725,289.23619 13.513722,263.49906 z M 428.50457,317.76287 249.79034,336.84174 47.782384,358.40473 c 5.959201,9.19899 12.564704,17.94104 19.771165,26.14436 L 244.45559,351.80755 428.50457,317.76287 z m 13.78484,5.21258 -188.36565,62.18449 -133.00232,43.89972 c 33.5632,20.10936 72.81152,31.66237 114.75828,31.66238 93.04288,0 172.8858,-56.87905 206.60969,-137.74659 z"
|
||||
id="path6327" />
|
||||
<path
|
||||
style="fill:url(#linearGradient4057);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
|
||||
d="m 235.67972,13.233984 c -35.92776,0 -69.88078,8.488655 -99.97572,23.558433 l 161.01996,129.174323 52.55342,42.16899 c 39.1477,-4.87501 74.57645,-12.22557 104.45528,-21.44082 C 430.89209,87.375898 341.89666,13.233985 235.67972,13.233984 z M 79.118968,77.210299 c -7.972854,7.813525 -15.354146,16.22165 -22.092394,25.146641 l 217.604986,107.30591 8.32792,4.11306 c 7.91353,-0.38016 15.72478,-0.85776 23.43626,-1.42532 L 275.3035,193.86221 79.118968,77.210299 z M 24.488653,162.95322 c -2.661786,7.58527 -4.921793,15.36128 -6.760069,23.29373 42.624133,13.3171 96.712956,22.78306 156.947626,26.67377 L 24.488653,162.95322 z"
|
||||
id="path3203" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 453.02106 452.89808"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="openlp-logo.svg"
|
||||
inkscape:export-filename="/home/raoul/Dropbox/OpenLPNewBrand/wiki.png"
|
||||
inkscape:export-xdpi="23.68"
|
||||
inkscape:export-ydpi="23.68"
|
||||
width="453.02106"
|
||||
height="452.89807"><metadata
|
||||
id="metadata3420"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3418" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="739"
|
||||
id="namedview3416"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="151.21623"
|
||||
inkscape:cy="240.04907"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="312"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg5740"
|
||||
fit-margin-left="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4307"
|
||||
originx="-7.1894622"
|
||||
originy="-7.2509281" /><sodipodi:guide
|
||||
position="368,452.89804"
|
||||
orientation="0,1"
|
||||
id="guide3418"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
|
||||
position="-1.6629762e-07,295.00004"
|
||||
orientation="1,0"
|
||||
id="guide3420"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
|
||||
position="453.021,273.00004"
|
||||
orientation="1,0"
|
||||
id="guide3422"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
|
||||
position="362,2.6917146e-05"
|
||||
orientation="0,1"
|
||||
id="guide3424"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" /></sodipodi:namedview><style
|
||||
type="text/css"
|
||||
id="style3407">
|
||||
.st0{fill:url(#rect4108_1_);}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style><linearGradient
|
||||
id="rect4108_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="472.42209"
|
||||
y1="595.45251"
|
||||
x2="58.062099"
|
||||
y2="524.92249"
|
||||
gradientTransform="matrix(0.96923727,0,0,0.96897412,28.933406,-281.34151)"><stop
|
||||
offset="0"
|
||||
style="stop-color:#1E468C"
|
||||
id="stop3410" /><stop
|
||||
offset="1"
|
||||
style="stop-color:#507FDA"
|
||||
id="stop3412" /></linearGradient><g
|
||||
id="g3567"
|
||||
inkscape:export-filename="/home/raoul/Projects/OpenLP/OpenLP/new-branding/resources/images/openlp-splash-screen.png"
|
||||
inkscape:export-xdpi="73.526482"
|
||||
inkscape:export-ydpi="73.526482"
|
||||
transform="translate(-30,-30)"><path
|
||||
inkscape:export-filename="/home/raoul/Projects/OpenLP/WebSite/new-brand/themes/openlp2v2/assets/images/logo.png"
|
||||
inkscape:export-ydpi="11.92"
|
||||
inkscape:export-xdpi="11.92"
|
||||
id="rect4108"
|
||||
d="M 256.50947,30 A 226.51075,226.44925 0 0 0 30,256.44798 226.51075,226.44925 0 0 0 256.50947,482.89808 226.51075,226.44925 0 0 0 483.02107,256.44798 226.51075,226.44925 0 0 0 256.50947,30 Z"
|
||||
style="fill:url(#rect4108_1_)"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
inkscape:export-filename="/home/raoul/Projects/OpenLP/WebSite/new-brand/themes/openlp2v2/assets/images/logo.png"
|
||||
inkscape:export-ydpi="11.92"
|
||||
inkscape:export-xdpi="11.92"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 256.51033,46.633891 c -115.94546,0 -209.871922,94.007299 -209.871922,209.814939 0,115.80763 93.926462,209.81494 209.871922,209.81494 115.94546,0 209.87192,-94.00731 209.87192,-209.81494 0,-115.80764 -93.92646,-209.814939 -209.87192,-209.814939 z m -0.63823,17.546612 c 106.15923,0 192.32054,86.137907 192.32054,192.268327 0,15.73878 -1.9147,31.37121 -5.74409,46.57828 L 308.31348,195.51423 169.92354,84.492035 C 196.6229,71.092804 225.98157,64.180503 255.8721,64.180503 Z M 121.20517,119.26623 289.91113,219.54777 426.49275,300.7939 289.2729,233.15969 102.27095,140.85388 c 5.74409,-7.6567 12.12641,-14.88804 18.93422,-21.58765 z M 74.295122,192.962 276.93375,260.38352 416.8129,306.9618 276.93375,272.29395 66.955456,220.39852 c 1.701951,-9.3582 4.148507,-18.5037 7.339666,-27.43652 z m -9.467106,86.3506 206.361644,22.11936 144.6659,15.52609 -149.13352,-4.25372 -196.469053,-5.63619 c -2.446555,-9.03916 -4.254879,-18.39735 -5.424971,-27.75554 l 0,0 z M 421.59964,325.99722 263.42451,355.24157 111.31257,383.42249 C 105.143,376.40385 99.39891,368.85349 94.293055,360.9841 L 267.9985,342.4804 421.59964,325.99722 Z m 11.91366,4.46641 c -40.84684,98.04833 -153.49476,144.52027 -251.56973,103.57818 -8.50976,-3.50933 -16.80677,-7.76305 -24.6783,-12.44215 l 114.34988,-37.7518 161.89815,-53.38423 z"
|
||||
class="st1"
|
||||
id="path6317" /></g></svg>
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 48 KiB |
137
scripts/appveyor-webhook.py
Executable file
137
scripts/appveyor-webhook.py
Executable file
@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
"""
|
||||
This script is used to trigger a build at appveyor. Since the code is not hosted
|
||||
on github the normal triggering mechanisms can't be use. The project is
|
||||
registered as subversion repository. A webhook is used to trigger new builds.
|
||||
The appveyor.yml used for the build is send to appveyor when calling the hook.
|
||||
"""
|
||||
import json
|
||||
import urllib
|
||||
import urllib.request
|
||||
import datetime
|
||||
import sys
|
||||
import time
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
appveyor_build_url = 'https://ci.appveyor.com/project/TomasGroth/openlp/build'
|
||||
appveyor_api_url = 'https://ci.appveyor.com/api/projects/TomasGroth/openlp'
|
||||
|
||||
webhook_element = \
|
||||
{
|
||||
'commit': {
|
||||
'author': {
|
||||
'email': 'contributer@openlp',
|
||||
'name': 'OpenLP Contributor'
|
||||
},
|
||||
'id': None,
|
||||
'message': None,
|
||||
'timestamp': datetime.datetime.now().isoformat()
|
||||
},
|
||||
'config': None,
|
||||
'repository': {
|
||||
'name': 'repo_name',
|
||||
'url': 'repo_url'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_version():
|
||||
"""
|
||||
Get the version of the branch.
|
||||
"""
|
||||
bzr = Popen(('bzr', 'tags'), stdout=PIPE)
|
||||
output = bzr.communicate()[0]
|
||||
code = bzr.wait()
|
||||
if code != 0:
|
||||
raise Exception('Error running bzr tags')
|
||||
lines = output.splitlines()
|
||||
if len(lines) == 0:
|
||||
tag = '0.0.0'
|
||||
revision = '0'
|
||||
else:
|
||||
tag, revision = lines[-1].decode('utf-8').split()
|
||||
bzr = Popen(('bzr', 'log', '--line', '-r', '-1'), stdout=PIPE)
|
||||
output, error = bzr.communicate()
|
||||
code = bzr.wait()
|
||||
if code != 0:
|
||||
raise Exception('Error running bzr log')
|
||||
latest = output.decode('utf-8').split(':')[0]
|
||||
version_string = latest == revision and tag or 'r%s' % latest
|
||||
# Save decimal version in case we need to do a portable build.
|
||||
version = latest == revision and tag or '%s.%s' % (tag, latest)
|
||||
return version_string, version
|
||||
|
||||
|
||||
def get_yml(branch):
|
||||
"""
|
||||
Returns the content of appveyor.yml and inserts the branch to be build
|
||||
"""
|
||||
f = open('appveyor.yml')
|
||||
yml_text = f.read()
|
||||
f.close()
|
||||
yml_text = yml_text.replace('BRANCHNAME', branch)
|
||||
if 'openlp-core/openlp/trunk' in branch:
|
||||
yml_text = yml_text.replace('BUILD_DOCS', '$TRUE')
|
||||
else:
|
||||
yml_text = yml_text.replace('BUILD_DOCS', '$FALSE')
|
||||
return yml_text
|
||||
|
||||
|
||||
def hook(webhook_url, yml):
|
||||
"""
|
||||
Activate the webhook to start the build
|
||||
"""
|
||||
webhook_element['config'] = yml
|
||||
webhook_element['commit']['message'] = 'Building ' + branch
|
||||
version_string, version = get_version()
|
||||
webhook_element['commit']['id'] = version_string
|
||||
request = urllib.request.Request(webhook_url)
|
||||
request.add_header('Content-Type', 'application/json;charset=utf-8')
|
||||
responce = urllib.request.urlopen(request, json.dumps(webhook_element).encode('utf-8'))
|
||||
if responce.getcode() != 204:
|
||||
print('An error happened when calling the webhook! Return code: %d' % responce.getcode())
|
||||
print(responce.read().decode('utf-8'))
|
||||
|
||||
|
||||
def get_appveyor_build_url(branch):
|
||||
"""
|
||||
Get the url of the build.
|
||||
"""
|
||||
responce = urllib.request.urlopen(appveyor_api_url)
|
||||
json_str = responce.read().decode('utf-8')
|
||||
build_json = json.loads(json_str)
|
||||
build_url = '%s/%s' % (appveyor_build_url, build_json['build']['version'])
|
||||
print('Check this URL for build status: %s' % build_url)
|
||||
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print('Usage: %s <webhook-url> <branch>' % sys.argv[0])
|
||||
else:
|
||||
webhook_url = sys.argv[1]
|
||||
branch = sys.argv[2]
|
||||
hook(webhook_url, get_yml(branch))
|
||||
# Wait 5 seconds to make sure the hook has been triggered
|
||||
time.sleep(5)
|
||||
get_appveyor_build_url(branch)
|
84
scripts/appveyor.yml
Normal file
84
scripts/appveyor.yml
Normal file
@ -0,0 +1,84 @@
|
||||
version: OpenLP-win-ci-b{build}
|
||||
|
||||
init:
|
||||
- choco install -y --force bzr
|
||||
- set PATH=C:\Program Files (x86)\Bazaar;%PATH%
|
||||
|
||||
clone_script:
|
||||
- bzr checkout --lightweight BRANCHNAME openlp-branch
|
||||
|
||||
environment:
|
||||
PYTHON: C:\\Python34
|
||||
|
||||
install:
|
||||
# Install dependencies from pypi
|
||||
- "%PYTHON%\\python.exe -m pip install sqlalchemy alembic chardet beautifulsoup4 Mako nose mock pyodbc psycopg2 pypiwin32 pyenchant"
|
||||
# Install mysql dependency
|
||||
- "%PYTHON%\\python.exe -m pip install http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df"
|
||||
# Download and install lxml and pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)
|
||||
- "%PYTHON%\\python.exe -m pip install https://get.openlp.org/win-sdk/lxml-3.6.4-cp34-cp34m-win32.whl"
|
||||
- "%PYTHON%\\python.exe -m pip install https://get.openlp.org/win-sdk/PyICU-1.9.5-cp34-cp34m-win32.whl"
|
||||
# Download and install PyQt5
|
||||
- curl -L -O http://downloads.sourceforge.net/project/pyqt/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32.exe
|
||||
- PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32.exe /S
|
||||
# Download and unpack mupdf
|
||||
- curl -O http://mupdf.com/downloads/archive/mupdf-1.9a-windows.zip
|
||||
- 7z x mupdf-1.9a-windows.zip
|
||||
- cp mupdf-1.9a-windows/mupdf.exe openlp-branch/mupdf.exe
|
||||
# Download and unpack mediainfo
|
||||
- curl -O https://mediaarea.net/download/binary/mediainfo/0.7.90/MediaInfo_CLI_0.7.90_Windows_i386.zip
|
||||
- mkdir MediaInfo
|
||||
- 7z x -oMediaInfo MediaInfo_CLI_0.7.90_Windows_i386.zip
|
||||
- cp MediaInfo\\MediaInfo.exe openlp-branch\\MediaInfo.exe
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- cd openlp-branch
|
||||
# Run the tests
|
||||
- "%PYTHON%\\python.exe -m nose -v tests"
|
||||
# Go back to the user root folder
|
||||
- cd..
|
||||
|
||||
after_test:
|
||||
# This is where we create a package using PyInstaller
|
||||
# First get PyInstaller
|
||||
- curl -L -O https://github.com/pyinstaller/pyinstaller/releases/download/v3.2/PyInstaller-3.2.zip
|
||||
- 7z x PyInstaller-3.2.zip
|
||||
# Install PyInstaller dependencies
|
||||
- "%PYTHON%\\python.exe -m pip install future pefile"
|
||||
# Download and install Inno Setup - used for packaging
|
||||
- curl -L -O http://www.jrsoftware.org/download.php/is-unicode.exe
|
||||
- is-unicode.exe /VERYSILENT /SUPPRESSMSGBOXES /SP-
|
||||
# Download and unpack portable-bundle
|
||||
- curl -O https://get.openlp.org/win-sdk/portable-setup.7z
|
||||
- 7z x portable-setup.7z
|
||||
# Disabled portable installers - can't figure out how to make them silent
|
||||
# - curl -L -O http://downloads.sourceforge.net/project/portableapps/PortableApps.com%20Installer/PortableApps.comInstaller_3.4.4.paf.exe
|
||||
# - PortableApps.comInstaller_3.4.4.paf.exe /S
|
||||
# - curl -L -O http://downloads.sourceforge.net/project/portableapps/PortableApps.com%20Launcher/PortableApps.comLauncher_2.2.1.paf.exe
|
||||
# - PortableApps.comLauncher_2.2.1.paf.exe /S
|
||||
# - curl -L -O http://downloads.sourceforge.net/project/portableapps/NSIS%20Portable/NSISPortable_3.0_English.paf.exe
|
||||
# - NSISPortable_3.0_English.paf.exe /S
|
||||
# Get the packaging code
|
||||
- curl -L http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -o packaging.tar.gz
|
||||
- 7z e packaging.tar.gz
|
||||
- 7z x packaging.tar
|
||||
- mv ~openlp-core/openlp/packaging packaging
|
||||
# If this is trunk we should also build the manual
|
||||
- ps: >-
|
||||
If (BUILD_DOCS) {
|
||||
&"$env:PYTHON\python.exe" -m pip install sphinx
|
||||
Invoke-WebRequest -Uri "http://bazaar.launchpad.net/~openlp-core/openlp/documentation/tarball" -OutFile documentation.tar.gz
|
||||
7z e documentation.tar.gz
|
||||
7z x documentation.tar
|
||||
mv ~openlp-core/openlp/documentation documentation
|
||||
cd packaging
|
||||
&"$env:PYTHON\python.exe" builders/windows-builder.py --skip-update --skip-translations -c windows/config-appveyor.ini -b ../openlp-branch -d ../documentation --portable
|
||||
} else {
|
||||
cd packaging
|
||||
&"$env:PYTHON\python.exe" builders/windows-builder.py --skip-update --skip-translations -c windows/config-appveyor.ini -b ../openlp-branch --portable
|
||||
}
|
||||
|
||||
artifacts:
|
||||
- path: openlp-branch\dist\*.exe
|
@ -22,28 +22,40 @@
|
||||
"""
|
||||
Functional tests to test the AppLocation class and related methods.
|
||||
"""
|
||||
import os
|
||||
import tempfile
|
||||
import socket
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.core.lib.webpagereader import _get_user_agent, get_web_page
|
||||
from openlp.core.common.httputils import get_user_agent, get_web_page, get_url_file_size, url_get_file
|
||||
|
||||
from tests.functional import MagicMock, patch
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
class TestUtils(TestCase):
|
||||
class TestHttpUtils(TestCase, TestMixin):
|
||||
|
||||
"""
|
||||
A test suite to test out various methods around the AppLocation class.
|
||||
A test suite to test out various http helper functions.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.tempfile = os.path.join(tempfile.gettempdir(), 'testfile')
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.isfile(self.tempfile):
|
||||
os.remove(self.tempfile)
|
||||
|
||||
def test_get_user_agent_linux(self):
|
||||
"""
|
||||
Test that getting a user agent on Linux returns a user agent suitable for Linux
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||
|
||||
# GIVEN: The system is Linux
|
||||
mocked_sys.platform = 'linux2'
|
||||
|
||||
# WHEN: We call _get_user_agent()
|
||||
user_agent = _get_user_agent()
|
||||
# WHEN: We call get_user_agent()
|
||||
user_agent = get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
result = 'Linux' in user_agent or 'CrOS' in user_agent
|
||||
@ -53,13 +65,13 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that getting a user agent on Windows returns a user agent suitable for Windows
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||
|
||||
# GIVEN: The system is Linux
|
||||
mocked_sys.platform = 'win32'
|
||||
|
||||
# WHEN: We call _get_user_agent()
|
||||
user_agent = _get_user_agent()
|
||||
# WHEN: We call get_user_agent()
|
||||
user_agent = get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent')
|
||||
@ -68,13 +80,13 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that getting a user agent on OS X returns a user agent suitable for OS X
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||
|
||||
# GIVEN: The system is Linux
|
||||
mocked_sys.platform = 'darwin'
|
||||
|
||||
# WHEN: We call _get_user_agent()
|
||||
user_agent = _get_user_agent()
|
||||
# WHEN: We call get_user_agent()
|
||||
user_agent = get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent')
|
||||
@ -83,13 +95,13 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||
with patch('openlp.core.common.httputils.sys') as mocked_sys:
|
||||
|
||||
# GIVEN: The system is Linux
|
||||
mocked_sys.platform = 'freebsd'
|
||||
|
||||
# WHEN: We call _get_user_agent()
|
||||
user_agent = _get_user_agent()
|
||||
# WHEN: We call get_user_agent()
|
||||
user_agent = get_user_agent()
|
||||
|
||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||
self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent')
|
||||
@ -111,9 +123,9 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that the get_web_page method works correctly
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent, \
|
||||
with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent, \
|
||||
patch('openlp.core.common.Registry') as MockRegistry:
|
||||
# GIVEN: Mocked out objects and a fake URL
|
||||
mocked_request_object = MagicMock()
|
||||
@ -141,9 +153,9 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that adding a header to the call to get_web_page() adds the header to the request
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent:
|
||||
with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent:
|
||||
# GIVEN: Mocked out objects, a fake URL and a fake header
|
||||
mocked_request_object = MagicMock()
|
||||
MockRequest.return_value = mocked_request_object
|
||||
@ -170,9 +182,9 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent:
|
||||
with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent:
|
||||
# GIVEN: Mocked out objects, a fake URL and a fake header
|
||||
mocked_request_object = MagicMock()
|
||||
MockRequest.return_value = mocked_request_object
|
||||
@ -189,7 +201,7 @@ class TestUtils(TestCase):
|
||||
mocked_request_object.add_header.assert_called_with(user_agent_header[0], user_agent_header[1])
|
||||
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
||||
'There should only be 1 call to add_header')
|
||||
self.assertEqual(0, mock_get_user_agent.call_count, '_get_user_agent should not have been called')
|
||||
self.assertEqual(0, mock_get_user_agent.call_count, 'get_user_agent should not have been called')
|
||||
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
||||
mocked_page_object.geturl.assert_called_with()
|
||||
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
||||
@ -198,10 +210,10 @@ class TestUtils(TestCase):
|
||||
"""
|
||||
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
|
||||
"""
|
||||
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent, \
|
||||
patch('openlp.core.lib.webpagereader.Registry') as MockRegistry:
|
||||
with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \
|
||||
patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent, \
|
||||
patch('openlp.core.common.httputils.Registry') as MockRegistry:
|
||||
# GIVEN: Mocked out objects, a fake URL
|
||||
mocked_request_object = MagicMock()
|
||||
MockRequest.return_value = mocked_request_object
|
||||
@ -227,3 +239,36 @@ class TestUtils(TestCase):
|
||||
mocked_registry_object.get.assert_called_with('application')
|
||||
mocked_application_object.process_events.assert_called_with()
|
||||
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
||||
|
||||
def test_get_url_file_size(self):
|
||||
"""
|
||||
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
|
||||
"""
|
||||
with patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \
|
||||
patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent:
|
||||
# GIVEN: Mocked out objects, a fake URL
|
||||
mocked_page_object = MagicMock()
|
||||
mock_urlopen.return_value = mocked_page_object
|
||||
mock_get_user_agent.return_value = 'user_agent'
|
||||
fake_url = 'this://is.a.fake/url'
|
||||
|
||||
# WHEN: The get_url_file_size() method is called
|
||||
size = get_url_file_size(fake_url)
|
||||
|
||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||
mock_urlopen.assert_called_with(fake_url, timeout=30)
|
||||
|
||||
@patch('openlp.core.ui.firsttimeform.urllib.request.urlopen')
|
||||
def test_socket_timeout(self, mocked_urlopen):
|
||||
"""
|
||||
Test socket timeout gets caught
|
||||
"""
|
||||
# GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download
|
||||
mocked_urlopen.side_effect = socket.timeout()
|
||||
|
||||
# WHEN: Attempt to retrieve a file
|
||||
url_get_file(MagicMock(), url='http://localhost/test', f_path=self.tempfile)
|
||||
|
||||
# THEN: socket.timeout should have been caught
|
||||
# NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files
|
||||
self.assertFalse(os.path.exists(self.tempfile), 'FTW url_get_file should have caught socket.timeout')
|
@ -32,16 +32,30 @@ from tests.helpers.testmixin import TestMixin
|
||||
|
||||
class TestFirstTimeForm(TestCase, TestMixin):
|
||||
|
||||
def test_on_volunteer_button_clicked(self):
|
||||
@patch('openlp.core.ui.aboutform.webbrowser')
|
||||
def test_on_volunteer_button_clicked(self, mocked_webbrowser):
|
||||
"""
|
||||
Test that clicking on the "Volunteer" button opens a web page.
|
||||
"""
|
||||
# GIVEN: A new About dialog and a mocked out webbrowser module
|
||||
with patch('openlp.core.ui.aboutform.webbrowser') as mocked_webbrowser:
|
||||
about_form = AboutForm(None)
|
||||
about_form = AboutForm(None)
|
||||
|
||||
# WHEN: The "Volunteer" button is "clicked"
|
||||
about_form.on_volunteer_button_clicked()
|
||||
# WHEN: The "Volunteer" button is "clicked"
|
||||
about_form.on_volunteer_button_clicked()
|
||||
|
||||
# THEN: A web browser is opened
|
||||
mocked_webbrowser.open_new.assert_called_with('http://openlp.org/en/contribute')
|
||||
# THEN: A web browser is opened
|
||||
mocked_webbrowser.open_new.assert_called_with('http://openlp.org/en/contribute')
|
||||
|
||||
@patch('openlp.core.ui.aboutform.get_application_version')
|
||||
def test_about_form_build_number(self, mocked_get_application_version):
|
||||
"""
|
||||
Test that the build number is added to the about form
|
||||
"""
|
||||
# GIVEN: A mocked out get_application_version function
|
||||
mocked_get_application_version.return_value = {'version': '3.1.5', 'build': '3000'}
|
||||
|
||||
# WHEN: The about form is created
|
||||
about_form = AboutForm(None)
|
||||
|
||||
# THEN: The build number should be in the text
|
||||
assert 'OpenLP 3.1.5 build 3000' in about_form.about_text_edit.toPlainText()
|
||||
|
@ -31,7 +31,7 @@ import urllib.parse
|
||||
from tests.functional import patch
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
from openlp.core.lib.webpagereader import CONNECTION_RETRIES, get_web_page
|
||||
from openlp.core.common.httputils import CONNECTION_RETRIES, get_web_page
|
||||
|
||||
|
||||
class TestFirstTimeWizard(TestMixin, TestCase):
|
||||
|
@ -23,7 +23,6 @@
|
||||
Package to test the openlp.core.ui.firsttimeform package.
|
||||
"""
|
||||
import os
|
||||
import socket
|
||||
import tempfile
|
||||
import urllib
|
||||
from unittest import TestCase
|
||||
@ -236,20 +235,3 @@ class TestFirstTimeForm(TestCase, TestMixin):
|
||||
# THEN: the critical_error_message_box should have been called
|
||||
self.assertEquals(mocked_message_box.mock_calls[1][1][0], 'Network Error 407',
|
||||
'first_time_form should have caught Network Error')
|
||||
|
||||
@patch('openlp.core.ui.firsttimeform.urllib.request.urlopen')
|
||||
def test_socket_timeout(self, mocked_urlopen):
|
||||
"""
|
||||
Test socket timeout gets caught
|
||||
"""
|
||||
# GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download
|
||||
first_time_form = FirstTimeForm(None)
|
||||
first_time_form.initialize(MagicMock())
|
||||
mocked_urlopen.side_effect = socket.timeout()
|
||||
|
||||
# WHEN: Attempt to retrieve a file
|
||||
first_time_form.url_get_file(url='http://localhost/test', f_path=self.tempfile)
|
||||
|
||||
# THEN: socket.timeout should have been caught
|
||||
# NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files
|
||||
self.assertFalse(os.path.exists(self.tempfile), 'FTW url_get_file should have caught socket.timeout')
|
||||
|
@ -270,6 +270,8 @@ class TestMainDisplay(TestCase, TestMixin):
|
||||
service_item = MagicMock()
|
||||
service_item.theme_data = MagicMock()
|
||||
service_item.theme_data.background_type = 'video'
|
||||
service_item.theme_data.theme_name = 'name'
|
||||
service_item.theme_data.background_filename = 'background_filename'
|
||||
mocked_plugin = MagicMock()
|
||||
display.plugin_manager = PluginManager()
|
||||
display.plugin_manager.plugins = [mocked_plugin]
|
||||
|
60
tests/functional/openlp_core_ui/test_shortcutlistdialog.py
Normal file
60
tests/functional/openlp_core_ui/test_shortcutlistdialog.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-2016 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
Package to test the openlp.core.ui.shortcutlistdialog package.
|
||||
"""
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from openlp.core.ui.shortcutlistdialog import CaptureShortcutButton, ShortcutTreeWidget
|
||||
|
||||
from tests.interfaces import MagicMock, patch
|
||||
|
||||
|
||||
def test_key_press_event():
|
||||
"""
|
||||
Test the keyPressEvent method
|
||||
"""
|
||||
# GIVEN: A checked button and a mocked event
|
||||
button = CaptureShortcutButton()
|
||||
button.setChecked(True)
|
||||
mocked_event = MagicMock()
|
||||
mocked_event.key.return_value = QtCore.Qt.Key_Space
|
||||
|
||||
# WHEN: keyPressEvent is called with an event that should be ignored
|
||||
button.keyPressEvent(mocked_event)
|
||||
|
||||
# THEN: The ignore() method on the event should have been called
|
||||
mocked_event.ignore.assert_called_once_with()
|
||||
|
||||
|
||||
def test_keyboard_search():
|
||||
"""
|
||||
Test the keyboardSearch method of the ShortcutTreeWidget
|
||||
"""
|
||||
# GIVEN: A ShortcutTreeWidget
|
||||
widget = ShortcutTreeWidget()
|
||||
|
||||
# WHEN: keyboardSearch() is called
|
||||
widget.keyboardSearch('')
|
||||
|
||||
# THEN: Nothing happens
|
||||
assert True
|
220
tests/functional/openlp_plugins/bibles/test_wordprojectimport.py
Normal file
220
tests/functional/openlp_plugins/bibles/test_wordprojectimport.py
Normal file
@ -0,0 +1,220 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
This module contains tests for the WordProject Bible importer.
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.plugins.bibles.lib.importers.wordproject import WordProjectBible
|
||||
from openlp.plugins.bibles.lib.db import BibleDB
|
||||
|
||||
from tests.functional import MagicMock, patch, call
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||
'..', '..', '..', 'resources', 'bibles'))
|
||||
INDEX_PAGE = open(os.path.join(TEST_PATH, 'wordproject_index.htm')).read()
|
||||
CHAPTER_PAGE = open(os.path.join(TEST_PATH, 'wordproject_chapter.htm')).read()
|
||||
|
||||
|
||||
class TestWordProjectImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`wordprojectimport` module.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry')
|
||||
self.addCleanup(self.registry_patcher.stop)
|
||||
self.registry_patcher.start()
|
||||
self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager')
|
||||
self.addCleanup(self.manager_patcher.stop)
|
||||
self.manager_patcher.start()
|
||||
|
||||
@patch('openlp.plugins.bibles.lib.importers.wordproject.os')
|
||||
@patch('openlp.plugins.bibles.lib.importers.wordproject.copen')
|
||||
def test_process_books(self, mocked_open, mocked_os):
|
||||
"""
|
||||
Test the process_books() method
|
||||
"""
|
||||
# GIVEN: A WordProject importer and a bunch of mocked things
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
importer.base_dir = ''
|
||||
importer.stop_import_flag = False
|
||||
importer.language_id = 'en'
|
||||
mocked_open.return_value.__enter__.return_value.read.return_value = INDEX_PAGE
|
||||
mocked_os.path.join.side_effect = lambda *x: ''.join(x)
|
||||
|
||||
# WHEN: process_books() is called
|
||||
with patch.object(importer, 'find_and_create_book') as mocked_find_and_create_book, \
|
||||
patch.object(importer, 'process_chapters') as mocked_process_chapters, \
|
||||
patch.object(importer, 'session') as mocked_session:
|
||||
importer.process_books()
|
||||
|
||||
# THEN: The right methods should have been called
|
||||
mocked_os.path.join.assert_called_once_with('', 'index.htm')
|
||||
mocked_open.assert_called_once_with('index.htm', encoding='utf-8', errors='ignore')
|
||||
assert mocked_find_and_create_book.call_count == 66, 'There should be 66 books'
|
||||
assert mocked_process_chapters.call_count == 66, 'There should be 66 books'
|
||||
assert mocked_session.commit.call_count == 66, 'There should be 66 books'
|
||||
|
||||
@patch('openlp.plugins.bibles.lib.importers.wordproject.os')
|
||||
@patch('openlp.plugins.bibles.lib.importers.wordproject.copen')
|
||||
def test_process_chapters(self, mocked_open, mocked_os):
|
||||
"""
|
||||
Test the process_chapters() method
|
||||
"""
|
||||
# GIVEN: A WordProject importer and a bunch of mocked things
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
importer.base_dir = ''
|
||||
importer.stop_import_flag = False
|
||||
importer.language_id = 'en'
|
||||
mocked_open.return_value.__enter__.return_value.read.return_value = CHAPTER_PAGE
|
||||
mocked_os.path.join.side_effect = lambda *x: ''.join(x)
|
||||
mocked_os.path.normpath.side_effect = lambda x: x
|
||||
mocked_db_book = MagicMock()
|
||||
mocked_db_book.name = 'Genesis'
|
||||
book_id = 1
|
||||
book_link = '01/1.htm'
|
||||
|
||||
# WHEN: process_chapters() is called
|
||||
with patch.object(importer, 'set_current_chapter') as mocked_set_current_chapter, \
|
||||
patch.object(importer, 'process_verses') as mocked_process_verses:
|
||||
importer.process_chapters(mocked_db_book, book_id, book_link)
|
||||
|
||||
# THEN: The right methods should have been called
|
||||
expected_set_current_chapter_calls = [call('Genesis', ch) for ch in range(1, 51)]
|
||||
expected_process_verses_calls = [call(mocked_db_book, 1, ch) for ch in range(1, 51)]
|
||||
mocked_os.path.join.assert_called_once_with('', '01/1.htm')
|
||||
mocked_open.assert_called_once_with('01/1.htm', encoding='utf-8', errors='ignore')
|
||||
assert mocked_set_current_chapter.call_args_list == expected_set_current_chapter_calls
|
||||
assert mocked_process_verses.call_args_list == expected_process_verses_calls
|
||||
|
||||
@patch('openlp.plugins.bibles.lib.importers.wordproject.os')
|
||||
@patch('openlp.plugins.bibles.lib.importers.wordproject.copen')
|
||||
def test_process_verses(self, mocked_open, mocked_os):
|
||||
"""
|
||||
Test the process_verses() method
|
||||
"""
|
||||
# GIVEN: A WordProject importer and a bunch of mocked things
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
importer.base_dir = ''
|
||||
importer.stop_import_flag = False
|
||||
importer.language_id = 'en'
|
||||
mocked_open.return_value.__enter__.return_value.read.return_value = CHAPTER_PAGE
|
||||
mocked_os.path.join.side_effect = lambda *x: '/'.join(x)
|
||||
mocked_db_book = MagicMock()
|
||||
mocked_db_book.name = 'Genesis'
|
||||
book_number = 1
|
||||
chapter_number = 1
|
||||
|
||||
# WHEN: process_verses() is called
|
||||
with patch.object(importer, 'process_verse') as mocked_process_verse:
|
||||
importer.process_verses(mocked_db_book, book_number, chapter_number)
|
||||
|
||||
# THEN: All the right methods should have been called
|
||||
mocked_os.path.join.assert_called_once_with('', '01', '1.htm')
|
||||
mocked_open.assert_called_once_with('/01/1.htm', encoding='utf-8', errors='ignore')
|
||||
assert mocked_process_verse.call_count == 31
|
||||
|
||||
def test_process_verse(self):
|
||||
"""
|
||||
Test the process_verse() method
|
||||
"""
|
||||
# GIVEN: An importer and a mocked method
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
mocked_db_book = MagicMock()
|
||||
mocked_db_book.id = 1
|
||||
chapter_number = 1
|
||||
verse_number = 1
|
||||
verse_text = ' In the beginning, God created the heavens and the earth '
|
||||
|
||||
# WHEN: process_verse() is called
|
||||
with patch.object(importer, 'create_verse') as mocked_create_verse:
|
||||
importer.process_verse(mocked_db_book, chapter_number, verse_number, verse_text)
|
||||
|
||||
# THEN: The create_verse() method should have been called
|
||||
mocked_create_verse.assert_called_once_with(1, 1, 1, 'In the beginning, God created the heavens and the earth')
|
||||
|
||||
def test_process_verse_no_text(self):
|
||||
"""
|
||||
Test the process_verse() method when there's no text
|
||||
"""
|
||||
# GIVEN: An importer and a mocked method
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
mocked_db_book = MagicMock()
|
||||
mocked_db_book.id = 1
|
||||
chapter_number = 1
|
||||
verse_number = 1
|
||||
verse_text = ''
|
||||
|
||||
# WHEN: process_verse() is called
|
||||
with patch.object(importer, 'create_verse') as mocked_create_verse:
|
||||
importer.process_verse(mocked_db_book, chapter_number, verse_number, verse_text)
|
||||
|
||||
# THEN: The create_verse() method should NOT have been called
|
||||
assert mocked_create_verse.call_count == 0
|
||||
|
||||
def test_do_import(self):
|
||||
"""
|
||||
Test the do_import() method
|
||||
"""
|
||||
# GIVEN: An importer and mocked methods
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
|
||||
# WHEN: do_import() is called
|
||||
with patch.object(importer, '_unzip_file') as mocked_unzip_file, \
|
||||
patch.object(importer, 'get_language_id') as mocked_get_language_id, \
|
||||
patch.object(importer, 'process_books') as mocked_process_books, \
|
||||
patch.object(importer, '_cleanup') as mocked_cleanup:
|
||||
mocked_get_language_id.return_value = 1
|
||||
result = importer.do_import()
|
||||
|
||||
# THEN: The correct methods should have been called
|
||||
mocked_unzip_file.assert_called_once_with()
|
||||
mocked_get_language_id.assert_called_once_with(None, bible_name='kj.zip')
|
||||
mocked_process_books.assert_called_once_with()
|
||||
mocked_cleanup.assert_called_once_with()
|
||||
assert result is True
|
||||
|
||||
def test_do_import_no_language(self):
|
||||
"""
|
||||
Test the do_import() method when the language is not available
|
||||
"""
|
||||
# GIVEN: An importer and mocked methods
|
||||
importer = WordProjectBible(MagicMock(), path='.', name='.', filename='kj.zip')
|
||||
|
||||
# WHEN: do_import() is called
|
||||
with patch.object(importer, '_unzip_file') as mocked_unzip_file, \
|
||||
patch.object(importer, 'get_language_id') as mocked_get_language_id, \
|
||||
patch.object(importer, 'process_books') as mocked_process_books, \
|
||||
patch.object(importer, '_cleanup') as mocked_cleanup:
|
||||
mocked_get_language_id.return_value = None
|
||||
result = importer.do_import()
|
||||
|
||||
# THEN: The correct methods should have been called
|
||||
mocked_unzip_file.assert_called_once_with()
|
||||
mocked_get_language_id.assert_called_once_with(None, bible_name='kj.zip')
|
||||
assert mocked_process_books.call_count == 0
|
||||
mocked_cleanup.assert_called_once_with()
|
||||
assert result is False
|
@ -137,7 +137,7 @@ class TestPowerpointDocument(TestCase, TestMixin):
|
||||
instance.goto_slide(42)
|
||||
|
||||
# THEN: mocked_critical_error_message_box should have been called
|
||||
mocked_critical_error_message_box.assert_called_with('Error', 'An error occurred in the Powerpoint '
|
||||
mocked_critical_error_message_box.assert_called_with('Error', 'An error occurred in the PowerPoint '
|
||||
'integration and the presentation will be stopped.'
|
||||
' Restart the presentation if you wish to '
|
||||
'present it.')
|
||||
|
@ -76,3 +76,34 @@ class TestEditSongForm(TestCase, TestMixin):
|
||||
|
||||
# THEN they should be valid
|
||||
self.assertTrue(valid, "The tags list should be valid")
|
||||
|
||||
@patch('openlp.plugins.songs.forms.editsongform.set_case_insensitive_completer')
|
||||
def test_load_objects(self, mocked_set_case_insensitive_completer):
|
||||
"""
|
||||
Test the _load_objects() method
|
||||
"""
|
||||
# GIVEN: A song edit form and some mocked stuff
|
||||
mocked_class = MagicMock()
|
||||
mocked_class.name = 'Author'
|
||||
mocked_combo = MagicMock()
|
||||
mocked_combo.count.return_value = 0
|
||||
mocked_cache = MagicMock()
|
||||
mocked_object = MagicMock()
|
||||
mocked_object.name = 'Charles'
|
||||
mocked_object.id = 1
|
||||
mocked_manager = MagicMock()
|
||||
mocked_manager.get_all_objects.return_value = [mocked_object]
|
||||
self.edit_song_form.manager = mocked_manager
|
||||
|
||||
# WHEN: _load_objects() is called
|
||||
self.edit_song_form._load_objects(mocked_class, mocked_combo, mocked_cache)
|
||||
|
||||
# THEN: All the correct methods should have been called
|
||||
self.edit_song_form.manager.get_all_objects.assert_called_once_with(mocked_class)
|
||||
mocked_combo.clear.assert_called_once_with()
|
||||
mocked_combo.count.assert_called_once_with()
|
||||
mocked_combo.addItem.assert_called_once_with('Charles')
|
||||
mocked_cache.append.assert_called_once_with('Charles')
|
||||
mocked_combo.setItemData.assert_called_once_with(0, 1)
|
||||
mocked_set_case_insensitive_completer.assert_called_once_with(mocked_cache, mocked_combo)
|
||||
mocked_combo.setEditText.assert_called_once_with('')
|
||||
|
@ -102,7 +102,7 @@ class TestInit(TestCase, TestMixin):
|
||||
mocked_question.return_value = QtWidgets.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install)
|
||||
self.openlp.backup_on_upgrade(old_install, False)
|
||||
|
||||
# THEN: It should not ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!')
|
||||
@ -120,14 +120,18 @@ class TestInit(TestCase, TestMixin):
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.0.5')
|
||||
self.openlp.splash = MagicMock()
|
||||
self.openlp.splash.isVisible.return_value = True
|
||||
with patch('openlp.core.get_application_version') as mocked_get_application_version,\
|
||||
patch('openlp.core.QtWidgets.QMessageBox.question') as mocked_question:
|
||||
mocked_get_application_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtWidgets.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install)
|
||||
self.openlp.backup_on_upgrade(old_install, True)
|
||||
|
||||
# THEN: It should ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
|
||||
self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
|
||||
self.openlp.splash.hide.assert_called_once_with()
|
||||
self.openlp.splash.show.assert_called_once_with()
|
||||
|
248
tests/resources/bibles/wordproject_chapter.htm
Normal file
248
tests/resources/bibles/wordproject_chapter.htm
Normal file
@ -0,0 +1,248 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Creation of the world, Genesis Chapter 1</title>
|
||||
<meta name="description" content="Creation of the world, Genesis Chapter 1" />
|
||||
<meta name="keywords" content="Holy Bible, Old Testament, scriptures, Creation, faith, heaven, hell, God, Jesus" />
|
||||
<!-- Mobile viewport optimisation -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../_assets/css/css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../_assets/css/style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../_assets/css/page-player.css" />
|
||||
|
||||
<!--[if lte IE 7]>
|
||||
<link href="../_assets/css/iehacks.css" rel="stylesheet" type="text/css" />
|
||||
<![endif]-->
|
||||
<!-- google analytics -->
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-39700598-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<!-- google analytics -->
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-39700598-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
<a name="mytop"></a>
|
||||
<body>
|
||||
<header class="ym-noprint">
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<h1><strong>Word</strong><em>Project</em></h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!--lang nav-->
|
||||
<!--nav id="nav">
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-hlist">
|
||||
<ul>
|
||||
<li><a title="Home" href="../../../index.htm" target="_top">Home</a></li>
|
||||
<li class="active"><a title="Bibles" href="../../../bibles/index.htm" target="_self">Bibles</a></li>
|
||||
<li><a title="Audio Bible" href="../../../bibles/audio/01_english/b01.htm" target="_top">Audio</a></li>
|
||||
<li><a title="Selected Bible Verses" href="../../../bibles/verses/english/index.htm" target="_top">Verses</a></li>
|
||||
<li><a title="Parallel Bibles" href="../../../bibles/parallel/index.htm" target="_top">Multi</a></li>
|
||||
<li><a title="Resourcces" href="../../../bibles/resources/index.htm" target="_top">Resources</a></li>
|
||||
<li><a title="Search" href="../../../bibles/search/index.htm" target="_top">Search</a></li>
|
||||
<li><a title="Download this Bible [language]" href="../../../download/bibles/index.htm" target="_top">Download</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav-->
|
||||
<div class="ym-wrapper ym-noprint">
|
||||
<div class="ym-wbox">
|
||||
<!--share buttons-->
|
||||
<div style="margin: 10px 1px 5px 20px;" align="right">
|
||||
<!-- Facebook -->
|
||||
<a title="Click to share on Facebook" href="http://www.facebook.com/sharer.php?u=http://wordproject.org/bibles/kj/01/1.htm" target="_blank"><img src="../_assets/img/facebook_2.png" alt="facebook" /></a>
|
||||
<!-- Twitter -->
|
||||
<a title="Click to share on Twitter" href="http://twitter.com/share?url=http://wordproject.org/bibles/kj/01/1.htm&text=Read this page &hashtags=wordproject" target="_blank"><img src="../_assets/img/twitter_2.png" alt="twitter" /></a>
|
||||
<!-- Google+ -->
|
||||
<a title="Click to share on Google plus" href="https://plus.google.com/share?url=http://wordproject.org/bibles/kj/01/1.htm" target="_blank"><img src="../_assets/img/google+_2.png" alt="google" /></a>
|
||||
<!-- LinkedIn -->
|
||||
<a title="Click to share on Linkedin" href="http://www.linkedin.com/shareArticle?mini=true&url=http://www.wordproject.org" target="_blank"><img src="../_assets/img/linkin_2.png" alt="linkin" /></a></p>
|
||||
</div>
|
||||
<!--/share buttons-->
|
||||
<div class=" ym-grid">
|
||||
<div class="ym-g62 ym-gl breadCrumbs"> <!--a title="Home" href="http://www.wordproject.org/index.htm" target="_top">Home</a> / <a title="Bibles" href="../../index.htm" target="_self">Bibles</a--> / <a href="../index.htm" target="_self">KJV</a></div>
|
||||
<div class="ym-g38 ym-gr alignRight ym-noprint"><a class="decreaseFont ym-button">-</a><a class="resetFont ym-button">Reset</a><a class="increaseFont ym-button">+</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="main" class="ym-clearfix" role="main">
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<div class="textOptions">
|
||||
<div class="textHeader">
|
||||
<h2>Genesis</h2>
|
||||
<a name="0"></a>
|
||||
<p class="ym-noprint"> Chapter:
|
||||
|
||||
<span class="c1">1</span>
|
||||
<a href="2.htm#0">2</a>
|
||||
<a href="3.htm#0">3</a>
|
||||
<a href="4.htm#0">4</a>
|
||||
<a href="5.htm#0">5</a>
|
||||
<a href="6.htm#0">6</a>
|
||||
<a href="7.htm#0">7</a>
|
||||
<a href="8.htm#0">8</a>
|
||||
<a href="9.htm#0">9</a>
|
||||
<a href="10.htm#0">10</a>
|
||||
<a href="11.htm#0">11</a>
|
||||
<a href="12.htm#0">12</a>
|
||||
<a href="13.htm#0">13</a>
|
||||
<a href="14.htm#0">14</a>
|
||||
<a href="15.htm#0">15</a>
|
||||
<a href="16.htm#0">16</a>
|
||||
<a href="17.htm#0">17</a>
|
||||
<a href="18.htm#0">18</a>
|
||||
<a href="19.htm#0">19</a>
|
||||
<a href="20.htm#0">20</a>
|
||||
<a href="21.htm#0">21</a>
|
||||
<a href="22.htm#0">22</a>
|
||||
<a href="23.htm#0">23</a>
|
||||
<a href="24.htm#0">24</a>
|
||||
<a href="25.htm#0">25</a>
|
||||
<a href="26.htm#0">26</a>
|
||||
<a href="27.htm#0">27</a>
|
||||
<a href="28.htm#0">28</a>
|
||||
<a href="29.htm#0">29</a>
|
||||
<a href="30.htm#0">30</a>
|
||||
<a href="31.htm#0">31</a>
|
||||
<a href="32.htm#0">32</a>
|
||||
<a href="33.htm#0">33</a>
|
||||
<a href="34.htm#0">34</a>
|
||||
<a href="35.htm#0">35</a>
|
||||
<a href="36.htm#0">36</a>
|
||||
<a href="37.htm#0">37</a>
|
||||
<a href="38.htm#0">38</a>
|
||||
<a href="39.htm#0">39</a>
|
||||
<a href="40.htm#0">40</a>
|
||||
<a href="41.htm#0">41</a>
|
||||
<a href="42.htm#0">42</a>
|
||||
<a href="43.htm#0">43</a>
|
||||
<a href="44.htm#0">44</a>
|
||||
<a href="45.htm#0">45</a>
|
||||
<a href="46.htm#0">46</a>
|
||||
<a href="47.htm#0">47</a>
|
||||
<a href="48.htm#0">48</a>
|
||||
<a href="49.htm#0">49</a>
|
||||
<a href="50.htm#0">50</a>
|
||||
<!--end of chapters-->
|
||||
</p>
|
||||
</div>
|
||||
<div class="textAudio ym-noprint"><ul class="playlist">
|
||||
<li class="noMargin">
|
||||
<!--start audio link--><a href="http://audio2.wordproject.com/bibles/app/audio/1/1/1.mp3">Genesis - Chapter 1 </a></li><!--/audioRef-->
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!--end audio-->
|
||||
<hr />
|
||||
<div class="textBody" id="textBody">
|
||||
<h3>Chapter 1</h3>
|
||||
|
||||
<!--... the Word of God:--></a>
|
||||
<p><span class="verse" id="1">1</span> In the beginning God created the heaven and the earth.
|
||||
<br /><span class="verse" id="2">2</span> And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.
|
||||
<br /><span class="verse" id="3">3</span> And God said, Let there be light: and there was light.
|
||||
<br /><span class="verse" id="4">4</span> And God saw the light, that it was good: and God divided the light from the darkness.
|
||||
<br /><span class="verse" id="5">5</span> And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.
|
||||
<br /><span class="verse" id="6">6</span> And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.
|
||||
<br /><span class="verse" id="7">7</span> And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.
|
||||
<br /><span class="verse" id="8">8</span> And God called the firmament Heaven. And the evening and the morning were the second day.
|
||||
<br /><span class="verse" id="9">9</span> And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.
|
||||
<br /><span class="verse" id="10">10</span> And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.
|
||||
<br /><span class="verse" id="11">11</span> And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.
|
||||
<br /><span class="verse" id="12">12</span> And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.
|
||||
<br /><span class="verse" id="13">13</span> And the evening and the morning were the third day.
|
||||
<br /><span class="verse" id="14">14</span> And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:
|
||||
<br /><span class="verse" id="15">15</span> And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.
|
||||
<br /><span class="verse" id="16">16</span> And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.
|
||||
<br /><span class="verse" id="17">17</span> And God set them in the firmament of the heaven to give light upon the earth,
|
||||
<br /><span class="verse" id="18">18</span> And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.
|
||||
<br /><span class="verse" id="19">19</span> And the evening and the morning were the fourth day.
|
||||
<br /><span class="verse" id="20">20</span> And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.
|
||||
<br /><span class="verse" id="21">21</span> And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.
|
||||
<br /><span class="verse" id="22">22</span> And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.
|
||||
<br /><span class="verse" id="23">23</span> And the evening and the morning were the fifth day.
|
||||
<br /><span class="verse" id="24">24</span> And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.
|
||||
<br /><span class="verse" id="25">25</span> And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.
|
||||
<br /><span class="verse" id="26">26</span> And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.
|
||||
<br /><span class="verse" id="27">27</span> So God created man in his own image, in the image of God created he him; male and female created he them.
|
||||
<br /><span class="verse" id="28">28</span> And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.
|
||||
<br /><span class="verse" id="29">29</span> And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.
|
||||
<br /><span class="verse" id="30">30</span> And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.
|
||||
<br /><span class="verse" id="31">31</span> And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.
|
||||
</p>
|
||||
<!--... sharper than any twoedged sword... -->
|
||||
</div>
|
||||
</div><!-- ym-wbox end -->
|
||||
</div><!-- ym-wrapper end -->
|
||||
</div><!-- ym-wrapper end -->
|
||||
</div><!-- ym-wrapper end -->
|
||||
<!--..sharper than any twoedged sword...-->
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<div class="alignRight ym-noprint">
|
||||
<p><a title="Print this page" href="javascript:window.print()" class="ym-button"> <img src="../_assets/img/printer.gif" alt="printer" width="25" height="25" align="absbottom" /> </a>
|
||||
<a class="ym-button" title="Page TOP" href="#mytop"> <img src="../_assets/img/arrow_up.png" alt="arrowup" width="25" height="25" align="absbottom" /> </a>
|
||||
<!--next chapter start-->
|
||||
<a class="ym-button" title="Next chapter" href="2.htm#0"> <img src="../_assets/img/arrow_right.png" alt="arrowright" align="absbottom" /> </a></p>
|
||||
<!--next chapter end-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<p class="alignCenter">Wordproject® is a registered name of the <a href="http://www.wordproject.org">International Biblical Association</a>, a non-profit organization registered in Macau, China. </p>
|
||||
<p class="alignCenter"><a href="http://www.wordproject.org/contact/new/index.htm" target="_top">Contact</a> | <a href="http://www.wordproject.org/contact/new/disclaim.htm" target="_top"> Disclaimer</a> |
|
||||
<a href="http://www.wordproject.org/contact/new/state.htm" target="_top">Statement of Faith</a> |
|
||||
<a href="http://www.wordproject.org/contact/new/mstate.htm" target="_top">Mission</a> |
|
||||
<a href="http://www.wordproject.org/contact/new/copyrights.htm" target="_top">Copyrights</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</script><script type="text/javascript" src="../_assets/js/jquery-1.8.0.min.js"></script>
|
||||
<script type="text/javascript" src="../_assets/js/soundmanager2.js"></script>
|
||||
<script type="text/javascript" src="../_assets/js/page-player.js"></script>
|
||||
<script type="text/javascript" src="../_assets/js/script.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
soundManager.setup({
|
||||
url: '../_assets/swf/'
|
||||
});
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
222
tests/resources/bibles/wordproject_index.htm
Normal file
222
tests/resources/bibles/wordproject_index.htm
Normal file
@ -0,0 +1,222 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>The Holy Bible in the English language with audio narration - KJV</title>
|
||||
<meta name="title" content="The Holy Bible in the English language with audio narration - KJV" />
|
||||
<meta name="description" content="Bible books: choose the book you wish to read or listen to" />
|
||||
<meta name="keywords" content="Bible, Holy, New testament, Old testament, Scriptures, God, Jesus" />
|
||||
<link rel="shortcut icon" href="http://www.wordproject.org/favicon.ico" />
|
||||
<meta name="robots" content="index, follow" />
|
||||
<!-- Mobile viewport optimisation -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="_assets/css/css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_assets/css/style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_assets/css/page-player.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_assets/css/tables_bibles.css" />
|
||||
|
||||
<!--[if lte IE 7]>
|
||||
<link href="_assets/css/iehacks.css" rel="stylesheet" type="text/css" />
|
||||
<![endif]-->
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<!-- google analytics -->
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-39700598-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
<!--
|
||||
.style1 {font-size: medium}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<a name="mytop"></a>
|
||||
<body>
|
||||
<header class="ym-noprint">
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<h1><strong>Word</strong><em>Project</em></h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!--index nav-->
|
||||
<!--nav id="nav">
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-hlist">
|
||||
<ul>
|
||||
<li><a title="Home" href="../../index.htm" target="_top">Home</a></li>
|
||||
<li class="active"><a title="Bibles" href="../../bibles/index.htm" target="_self">Bibles</a></li>
|
||||
<li><a title="Audio Bible" href="../../bibles/audio/index.htm" target="_top">Audio</a></li>
|
||||
<li><a title="Selected Bible Verses" href="../../bibles/verses/index.htm" target="_top">Verses</a></li>
|
||||
<li><a title="Parallel Bibles" href="../../bibles/parallel/index.htm" target="_top">Multi</a></li>
|
||||
<li><a title="Resourcces" href="../../bibles/resources/index.htm" target="_top">Resources</a></li>
|
||||
<li><a title="Search" href="../../bibles/search/index.htm" target="_top">Search</a></li>
|
||||
<li><a title="Download this Bible [language]" href="../../download/bibles/index.htm" target="_top">Download</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav-->
|
||||
<div class="ym-wrapper ym-noprint">
|
||||
<div class="ym-wbox">
|
||||
<!--share buttons-->
|
||||
<div style="margin: 10px 1px 5px 20px;" align="right">
|
||||
<!-- Facebook -->
|
||||
<a title="Click to share on Facebook" href="http://www.facebook.com/sharer.php?u=http://wordproject.org/bibles/kj/index.htm" target="_blank"><img src="_assets/img/facebook_2.png" alt="facebook" /></a>
|
||||
<!-- Twitter -->
|
||||
<a title="Click to share on Twitter" href="http://twitter.com/share?url=http://wordproject.org/bibles/kj/index.htm&text=Read this page &hashtags=wordproject" target="_blank"><img src="_assets/img/twitter_2.png" alt="twitter" /></a>
|
||||
<!-- Google+ -->
|
||||
<a title="Click to share on Google plus" href="https://plus.google.com/share?url=http://wordproject.org/bibles/kj/index.htm" target="_blank"><img src="_assets/img/google+_2.png" alt="google" /></a>
|
||||
<!-- LinkedIn -->
|
||||
<a title="Click to share on Linkedin" href="http://www.linkedin.com/shareArticle?mini=true&url=http://www.wordproject.org" target="_blank"><img src="_assets/img/linkin_2.png" alt="linkin" /></a></p>
|
||||
</div>
|
||||
<!--/share buttons-->
|
||||
<div class=" ym-grid">
|
||||
<div class="ym-g62 ym-gl breadCrumbs"> <a title="Home" href="http://www.wordproject.org/index.htm" target="_top">Home</a> / <!--a title="Bibles" href="../index.htm" target="_self">Bibles</a--> / </div>
|
||||
<div class="ym-g38 ym-gr alignRight ym-noprint"><a class="decreaseFont ym-button">-</a><a class="resetFont ym-button">Reset</a><a class="increaseFont ym-button">+</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="main" class="ym-clearfix" role="main">
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<div class="textOptions">
|
||||
<div class="textHeader">
|
||||
<h2>English Bible </h2><span class="faded">King James Version</span>
|
||||
<a name="0"></a>
|
||||
<p class="faded">Please, choose a book of the Holy Bible in the English language:</p>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="ym-grid linearize-level-2">
|
||||
<!-- chapter list -->
|
||||
<div class="ym-g50 ym-gl">
|
||||
<h3>Old Testament</h3>
|
||||
<ul id="maintab" class="shadetabs">
|
||||
<li><a href="01/1.htm">[1] Genesis <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="02/1.htm">[2] Exodus <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="03/1.htm">[3] Leviticus <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="04/1.htm">[4] Numbers <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="05/1.htm">[5] Deuteronomy <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="06/1.htm">[6] Joshua <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="07/1.htm">[7] Judges <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="08/1.htm">[8] Ruth <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="09/1.htm">[9] 1 Samuel <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="10/1.htm">[10] 2 Samuel <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="11/1.htm">[11] 1 Kings <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="12/1.htm">[12] 2 Kings <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="13/1.htm">[13] 1 Chronicles <i class="icon-headphones pull-right"></i> </a></li>
|
||||
<li><a href="14/1.htm">[14] 2 Chronicles <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="15/1.htm">[15] Ezra <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="16/1.htm">[16] Nehemiah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="17/1.htm">[17] Esther <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="18/1.htm">[18] Job <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="19/1.htm">[19] Psalms <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="20/1.htm">[20] Proverbs <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="21/1.htm">[21] Ecclesiastes <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="22/1.htm">[22] Song of Songs <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="23/1.htm">[23] Isaiah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="24/1.htm">[24] Jeremiah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="25/1.htm">[25] Lamentations <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="26/1.htm">[26] Ezekiel <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="27/1.htm">[27] Daniel <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="28/1.htm">[28] Hosea <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="29/1.htm">[29] Joel <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="30/1.htm">[30] Amos <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="31/1.htm">[31] Obadiah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="32/1.htm">[32] Jonah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="33/1.htm">[33] Micah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="34/1.htm">[34] Nahum <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="35/1.htm">[35] Habakkuk <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="36/1.htm">[36] Zephaniah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="37/1.htm">[37] Haggai <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="38/1.htm">[38] Zechariah <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="39/1.htm">[39] Malachi <i class="icon-headphones pull-right"></i></a></li>
|
||||
</ul>
|
||||
</div> <div class="ym-g50 ym-gr">
|
||||
<h3>New Testament</h3>
|
||||
<ul id="maintab" class="shadetabs">
|
||||
<li><a href="40/1.htm">[40] Matthew <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="41/1.htm">[41] Mark <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="42/1.htm">[42] Luke <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="43/1.htm">[43] John <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="44/1.htm">[44] Acts <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="45/1.htm">[45] Romans <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="46/1.htm">[46] 1 Corinthians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="47/1.htm">[47] 2 Corinthians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="48/1.htm">[48] Galatians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="49/1.htm">[49] Ephesians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="50/1.htm">[50] Philippians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="51/1.htm">[51] Colossians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="52/1.htm">[52] 1 Thessalonians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="53/1.htm">[53] 2 Thessalonians <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="54/1.htm">[54] 1 Timothy <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li> <a href="55/1.htm">[55] 2 Timothy <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="56/1.htm">[56] Titus <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="57/1.htm">[57] Philemon <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="58/1.htm">[58] Hebrews <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="59/1.htm">[59] James <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li> <a href="60/1.htm">[60] 1 Peter <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="61/1.htm">[61] 2 Peter <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li> <a href="62/1.htm">[62] 1 John <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="63/1.htm">[63] 2 John <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="64/1.htm">[64] 3 John <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="65/1.htm">[65] Jude <i class="icon-headphones pull-right"></i></a></li>
|
||||
<li><a href="66/1.htm">[66] Revelation <i class="icon-headphones pull-right"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- end chapter list -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- ym-wbox end -->
|
||||
</div><!-- ym-wrapper end -->
|
||||
</div><!-- ym-wrapper end -->
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<div class="alignRight ym-noprint">
|
||||
<p><a class="ym-button" href="#mytop"><i class="icon-circle-arrow-up icon-white"></i> Top</a>
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class="ym-wrapper">
|
||||
<div class="ym-wbox">
|
||||
<p class="alignCenter">Wordproject® is a registered name of the <a href="http://www.wordproject.org">International Biblical Association</a>, a non-profit organization registered in Macau, China. </p>
|
||||
<p class="alignCenter"><a href="http://www.wordproject.org/contact/new/index.htm" target="_top">Contact</a> | <a href="http://www.wordproject.org/contact/new/disclaim.htm" target="_top"> Disclaimer</a> |
|
||||
<a href="http://www.wordproject.org/contact/new/state.htm" target="_top">Statement of Faith</a> |
|
||||
<a href="http://www.wordproject.org/contact/new/mstate.htm" target="_top">Mission</a> |
|
||||
<a href="http://www.wordproject.org/contact/new/copyrights.htm" target="_top">Copyrights</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</script><script type="text/javascript" src="_assets/js/jquery-1.8.0.min.js"></script>
|
||||
<script type="text/javascript" src="_assets/js/soundmanager2.js"></script>
|
||||
<script type="text/javascript" src="_assets/js/page-player.js"></script>
|
||||
<script type="text/javascript" src="_assets/js/script.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
soundManager.setup({
|
||||
url: '_assets/swf/'
|
||||
});
|
||||
|
||||
</script>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user