openlp/openlp/plugins/bibles/lib/__init__.py

447 lines
18 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2013-01-01 16:33:41 +00:00
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2012-12-29 20:56:56 +00:00
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
2012-11-11 21:16:14 +00:00
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
2012-10-21 13:16:22 +00:00
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
2010-07-29 14:36:02 +00:00
"""
The :mod:`lib` module contains all the library functionality for the bibles
plugin.
"""
import logging
import re
2012-05-17 15:13:09 +00:00
from openlp.core.lib import translate, Settings
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
2010-07-29 14:36:02 +00:00
log = logging.getLogger(__name__)
REFERENCE_MATCHES = {}
REFERENCE_SEPARATORS = {}
2011-02-18 03:15:09 +00:00
class LayoutStyle(object):
"""
An enumeration for bible screen layout styles.
"""
VersePerSlide = 0
VersePerLine = 1
Continuous = 2
class DisplayStyle(object):
"""
An enumeration for bible text bracket display styles.
"""
NoBrackets = 0
Round = 1
Curly = 2
Square = 3
class LanguageSelection(object):
"""
An enumeration for bible bookname language.
And standard strings for use throughout the bibles plugin.
"""
Bible = 0
Application = 1
English = 2
2012-03-04 21:50:32 +00:00
class BibleStrings(object):
"""
Provide standard strings for objects to use.
"""
__instance__ = None
def __new__(cls):
"""
Override the default object creation method to return a single instance.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
def __init__(self):
"""
These strings should need a good reason to be retranslated elsewhere.
"""
self.BookNames = {
u'Gen': translate('BiblesPlugin', 'Genesis'),
u'Exod': translate('BiblesPlugin', 'Exodus'),
u'Lev': translate('BiblesPlugin', 'Leviticus'),
u'Num': translate('BiblesPlugin', 'Numbers'),
u'Deut': translate('BiblesPlugin', 'Deuteronomy'),
u'Josh': translate('BiblesPlugin', 'Joshua'),
u'Judg': translate('BiblesPlugin', 'Judges'),
u'Ruth': translate('BiblesPlugin', 'Ruth'),
u'1Sam': translate('BiblesPlugin', '1 Samuel'),
u'2Sam': translate('BiblesPlugin', '2 Samuel'),
u'1Kgs': translate('BiblesPlugin', '1 Kings'),
u'2Kgs': translate('BiblesPlugin', '2 Kings'),
u'1Chr': translate('BiblesPlugin', '1 Chronicles'),
u'2Chr': translate('BiblesPlugin', '2 Chronicles'),
u'Esra': translate('BiblesPlugin', 'Ezra'),
u'Neh': translate('BiblesPlugin', 'Nehemiah'),
u'Esth': translate('BiblesPlugin', 'Esther'),
u'Job': translate('BiblesPlugin', 'Job'),
u'Ps': translate('BiblesPlugin', 'Psalms'),
u'Prov': translate('BiblesPlugin', 'Proverbs'),
u'Eccl': translate('BiblesPlugin', 'Ecclesiastes'),
u'Song': translate('BiblesPlugin', 'Song of Solomon'),
u'Isa': translate('BiblesPlugin', 'Isaiah'),
u'Jer': translate('BiblesPlugin', 'Jeremiah'),
u'Lam': translate('BiblesPlugin', 'Lamentations'),
u'Ezek': translate('BiblesPlugin', 'Ezekiel'),
u'Dan': translate('BiblesPlugin', 'Daniel'),
u'Hos': translate('BiblesPlugin', 'Hosea'),
u'Joel': translate('BiblesPlugin', 'Joel'),
u'Amos': translate('BiblesPlugin', 'Amos'),
u'Obad': translate('BiblesPlugin', 'Obadiah'),
u'Jonah': translate('BiblesPlugin', 'Jonah'),
u'Mic': translate('BiblesPlugin', 'Micah'),
u'Nah': translate('BiblesPlugin', 'Nahum'),
u'Hab': translate('BiblesPlugin', 'Habakkuk'),
u'Zeph': translate('BiblesPlugin', 'Zephaniah'),
u'Hag': translate('BiblesPlugin', 'Haggai'),
u'Zech': translate('BiblesPlugin', 'Zechariah'),
u'Mal': translate('BiblesPlugin', 'Malachi'),
u'Matt': translate('BiblesPlugin', 'Matthew'),
u'Mark': translate('BiblesPlugin', 'Mark'),
u'Luke': translate('BiblesPlugin', 'Luke'),
u'John': translate('BiblesPlugin', 'John'),
u'Acts': translate('BiblesPlugin', 'Acts'),
u'Rom': translate('BiblesPlugin', 'Romans'),
u'1Cor': translate('BiblesPlugin', '1 Corinthians'),
u'2Cor': translate('BiblesPlugin', '2 Corinthians'),
u'Gal': translate('BiblesPlugin', 'Galatians'),
u'Eph': translate('BiblesPlugin', 'Ephesians'),
u'Phil': translate('BiblesPlugin', 'Philippians'),
u'Col': translate('BiblesPlugin', 'Colossians'),
u'1Thess': translate('BiblesPlugin', '1 Thessalonians'),
u'2Thess': translate('BiblesPlugin', '2 Thessalonians'),
u'1Tim': translate('BiblesPlugin', '1 Timothy'),
u'2Tim': translate('BiblesPlugin', '2 Timothy'),
u'Titus': translate('BiblesPlugin', 'Titus'),
u'Phlm': translate('BiblesPlugin', 'Philemon'),
u'Heb': translate('BiblesPlugin', 'Hebrews'),
u'Jas': translate('BiblesPlugin', 'James'),
u'1Pet': translate('BiblesPlugin', '1 Peter'),
u'2Pet': translate('BiblesPlugin', '2 Peter'),
u'1John': translate('BiblesPlugin', '1 John'),
u'2John': translate('BiblesPlugin', '2 John'),
u'3John': translate('BiblesPlugin', '3 John'),
u'Jude': translate('BiblesPlugin', 'Jude'),
u'Rev': translate('BiblesPlugin', 'Revelation'),
u'Jdt': translate('BiblesPlugin', 'Judith'),
u'Wis': translate('BiblesPlugin', 'Wisdom'),
u'Tob': translate('BiblesPlugin', 'Tobit'),
u'Sir': translate('BiblesPlugin', 'Sirach'),
u'Bar': translate('BiblesPlugin', 'Baruch'),
u'1Macc': translate('BiblesPlugin', '1 Maccabees'),
u'2Macc': translate('BiblesPlugin', '2 Maccabees'),
u'3Macc': translate('BiblesPlugin', '3 Maccabees'),
u'4Macc': translate('BiblesPlugin', '4 Maccabees'),
u'AddDan': translate('BiblesPlugin', 'Rest of Daniel'),
u'AddEsth': translate('BiblesPlugin', 'Rest of Esther'),
u'PrMan': translate('BiblesPlugin', 'Prayer of Manasses'),
u'LetJer': translate('BiblesPlugin', 'Letter of Jeremiah'),
u'PrAza': translate('BiblesPlugin', 'Prayer of Azariah'),
u'Sus': translate('BiblesPlugin', 'Susanna'),
u'Bel': translate('BiblesPlugin', 'Bel'),
u'1Esdr': translate('BiblesPlugin', '1 Esdras'),
u'2Esdr': translate('BiblesPlugin', '2 Esdras')
2012-03-04 21:50:32 +00:00
}
2011-02-18 03:15:09 +00:00
def update_reference_separators():
2011-02-07 16:29:06 +00:00
"""
Updates separators and matches for parsing and formating scripture
2011-02-07 16:29:06 +00:00
references.
"""
2012-05-17 18:57:01 +00:00
default_separators = translate('BiblesPlugin',
2013-01-01 16:33:41 +00:00
':|v|V|verse|verses;;-|to;;,|and;;end Double-semicolon delimited separators for parsing references. '
2012-05-17 18:57:01 +00:00
'Consult the developers for further information.').split(u';;')
2012-05-17 15:13:09 +00:00
settings = Settings()
settings.beginGroup(u'bibles')
custom_separators = [
2012-05-17 16:19:06 +00:00
settings.value(u'verse separator', u''),
settings.value(u'range separator', u''),
settings.value(u'list separator', u''),
settings.value(u'end separator', u'')]
settings.endGroup()
for index, role in enumerate([u'v', u'r', u'l', u'e']):
if custom_separators[index].strip(u'|') == u'':
source_string = default_separators[index].strip(u'|')
else:
source_string = custom_separators[index].strip(u'|')
while u'||' in source_string:
source_string = source_string.replace(u'||', u'|')
if role != u'e':
2013-01-01 16:33:41 +00:00
REFERENCE_SEPARATORS[u'sep_%s_display' % role] = source_string.split(u'|')[0]
# escape reserved characters
for character in u'\\.^$*+?{}[]()':
source_string = source_string.replace(character, u'\\' + character)
# add various unicode alternatives
source_string = source_string.replace(u'-',
u'(?:[-\u00AD\u2010\u2011\u2012\u2013\u2014\u2212\uFE63\uFF0D])')
source_string = source_string.replace(u',', u'(?:[,\u201A])')
REFERENCE_SEPARATORS[u'sep_%s' % role] = u'\s*(?:%s)\s*' % source_string
2013-01-01 16:33:41 +00:00
REFERENCE_SEPARATORS[u'sep_%s_default' % role] = default_separators[index]
2010-12-18 02:12:41 +00:00
# verse range match: (<chapter>:)?<verse>(-((<chapter>:)?<verse>|end)?)?
range_regex = u'(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?' \
u'(?P<from_verse>[0-9]+)(?P<range_to>%(sep_r)s(?:(?:(?P<to_chapter>' \
2013-01-01 16:33:41 +00:00
u'[0-9]+)%(sep_v)s)?(?P<to_verse>[0-9]+)|%(sep_e)s)?)?' % REFERENCE_SEPARATORS
REFERENCE_MATCHES[u'range'] = re.compile(u'^\s*%s\s*$' % range_regex, re.UNICODE)
REFERENCE_MATCHES[u'range_separator'] = re.compile(REFERENCE_SEPARATORS[u'sep_l'], re.UNICODE)
# full reference match: <book>(<range>(,(?!$)|(?=$)))+
2013-01-01 16:33:41 +00:00
REFERENCE_MATCHES[u'full'] = re.compile(u'^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*'
u'(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$' \
2013-01-01 16:33:41 +00:00
% dict(REFERENCE_SEPARATORS.items() + [(u'range_regex', range_regex)]), re.UNICODE)
def get_reference_separator(separator_type):
"""
Provides separators for parsing and formatting scripture references.
``separator_type``
The role and format of the separator.
"""
if not REFERENCE_SEPARATORS:
update_reference_separators()
return REFERENCE_SEPARATORS[separator_type]
def get_reference_match(match_type):
"""
Provides matches for parsing scripture references strings.
``match_type``
The type of match is ``range_separator``, ``range`` or ``full``.
"""
if not REFERENCE_MATCHES:
update_reference_separators()
return REFERENCE_MATCHES[match_type]
def parse_reference(reference, bible, language_selection, book_ref_id=False):
"""
This is the next generation über-awesome function that takes a person's
typed in string and converts it to a list of references to be queried from
the Bible database files.
``reference``
A string. The Bible reference to parse.
2012-04-04 07:26:51 +00:00
``bible``
A object. The Bible database object.
2012-04-04 07:26:51 +00:00
``language_selection``
An int. The language selection the user has choosen in settings
section.
2012-04-04 07:26:51 +00:00
``book_ref_id``
A string. The book reference id.
Returns ``None`` or a reference list.
The reference list is a list of tuples, with each tuple structured like
this::
(book, chapter, from_verse, to_verse)
For example::
[(u'John', 3, 16, 18), (u'John', 4, 1, 1)]
**Reference string details:**
Each reference starts with the book name and a chapter number. These are
both mandatory.
* ``John 3`` refers to Gospel of John chapter 3
A reference range can be given after a range separator.
* ``John 3-5`` refers to John chapters 3 to 5
Single verses can be addressed after a verse separator.
* ``John 3:16`` refers to John chapter 3 verse 16
* ``John 3:16-4:3`` refers to John chapter 3 verse 16 to chapter 4 verse 3
After a verse reference all further single values are treat as verse in
the last selected chapter.
* ``John 3:16-18`` refers to John chapter 3 verses 16 to 18
After a list separator it is possible to refer to additional verses. They
are build analog to the first ones. This way it is possible to define each
number of verse references. It is not possible to refer to verses in
additional books.
* ``John 3:16,18`` refers to John chapter 3 verses 16 and 18
* ``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20
* ``John 3:16-18,4:1`` refers to John chapter 3 verses 16 to 18 and
chapter 4 verse 1
If there is a range separator without further verse declaration the last
refered chapter is addressed until the end.
``range_regex`` is a regular expression which matches for verse range
declarations:
``(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?``
It starts with a optional chapter reference ``from_chapter`` followed by
a verse separator.
``(?P<from_verse>[0-9]+)``
The verse reference ``from_verse`` is manditory
``(?P<range_to>%(sep_r)s(?:`` ... ``|%(sep_e)s)?)?``
A ``range_to`` declaration is optional. It starts with a range separator
2010-12-17 13:21:55 +00:00
and contains optional a chapter and verse declaration or a end
separator.
``(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?``
The ``to_chapter`` reference with separator is equivalent to group 1.
``(?P<to_verse>[0-9]+)``
The ``to_verse`` reference is equivalent to group 2.
2011-02-03 17:20:41 +00:00
The full reference is matched against get_reference_match(u'full'). This
2010-12-17 13:21:55 +00:00
regular expression looks like this:
``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
2011-02-03 17:20:41 +00:00
The ``book`` group starts with the first non-whitespace character. There
are optional leading digits followed by non-digits. The group ends
before the whitspace in front of the next digit.
``(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$``
2011-02-03 17:20:41 +00:00
The second group contains all ``ranges``. This can be multiple
declarations of range_regex separated by a list separator.
"""
log.debug(u'parse_reference("%s")', reference)
2010-12-17 13:21:55 +00:00
match = get_reference_match(u'full').match(reference)
if match:
log.debug(u'Matched reference %s' % reference)
book = match.group(u'book')
if not book_ref_id:
2013-01-01 16:33:41 +00:00
book_ref_id = bible.get_book_ref_id_by_localised_name(book, language_selection)
elif not bible.get_book_by_book_ref_id(book_ref_id):
book_ref_id = False
2010-12-17 13:21:55 +00:00
ranges = match.group(u'ranges')
range_list = get_reference_match(u'range_separator').split(ranges)
ref_list = []
chapter = None
2010-12-17 13:21:55 +00:00
for this_range in range_list:
range_match = get_reference_match(u'range').match(this_range)
from_chapter = range_match.group(u'from_chapter')
from_verse = range_match.group(u'from_verse')
has_range = range_match.group(u'range_to')
to_chapter = range_match.group(u'to_chapter')
to_verse = range_match.group(u'to_verse')
if from_chapter:
from_chapter = int(from_chapter)
if from_verse:
from_verse = int(from_verse)
if to_chapter:
to_chapter = int(to_chapter)
if to_verse:
to_verse = int(to_verse)
2010-12-17 13:21:55 +00:00
# Fill chapter fields with reasonable values.
if from_chapter:
chapter = from_chapter
elif chapter:
from_chapter = chapter
else:
from_chapter = from_verse
from_verse = None
if to_chapter:
if to_chapter < from_chapter:
continue
else:
chapter = to_chapter
elif to_verse:
if chapter:
to_chapter = chapter
else:
to_chapter = to_verse
to_verse = None
# Append references to the list
if has_range:
if not from_verse:
from_verse = 1
if not to_verse:
to_verse = -1
if to_chapter > from_chapter:
ref_list.append((book_ref_id, from_chapter, from_verse, -1))
2011-01-21 16:20:47 +00:00
for i in range(from_chapter + 1, to_chapter):
ref_list.append((book_ref_id, i, 1, -1))
ref_list.append((book_ref_id, to_chapter, 1, to_verse))
2010-12-17 13:21:55 +00:00
elif to_verse >= from_verse or to_verse == -1:
2013-01-01 16:33:41 +00:00
ref_list.append((book_ref_id, from_chapter, from_verse, to_verse))
elif from_verse:
2013-01-01 16:33:41 +00:00
ref_list.append((book_ref_id, from_chapter, from_verse, from_verse))
else:
ref_list.append((book_ref_id, from_chapter, 1, -1))
return ref_list
2010-07-29 14:36:02 +00:00
else:
log.debug(u'Invalid reference: %s' % reference)
return None
class SearchResults(object):
"""
Encapsulate a set of search results. This is Bible-type independent.
2010-07-29 14:36:02 +00:00
"""
def __init__(self, book, chapter, verselist):
"""
Create the search result object.
``book``
The book of the Bible.
``chapter``
The chapter of the book.
``verselist``
The list of verses for this reading.
2010-07-29 14:36:02 +00:00
"""
self.book = book
self.chapter = chapter
self.verselist = verselist
def has_verselist(self):
"""
Returns whether or not the verse list contains verses.
"""
return len(self.verselist) > 0
2011-03-20 20:50:19 +00:00
from versereferencelist import VerseReferenceList
2009-01-20 19:50:37 +00:00
from manager import BibleManager
from biblestab import BiblesTab
from mediaitem import BibleMediaItem