This commit is contained in:
rimach 2010-03-23 16:18:06 +01:00
commit 1667e58472
15 changed files with 220 additions and 113 deletions

View File

@ -148,6 +148,8 @@ class SongXMLParser(object):
verse_list = []
for element in iter:
if element.tag == u'verse':
if element.text is None:
element.text = u''
verse_list.append([element.attrib,
unicode(element.text).decode('unicode-escape')])
return verse_list

View File

@ -23,7 +23,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import os
import logging
import time
@ -68,7 +67,8 @@ class VersionThread(QtCore.QThread):
"""
Run the thread.
"""
time.sleep(2)
time.sleep(1)
Receiver.send_message(u'blank_check')
version = check_latest_version(self.generalConfig, self.app_version)
#new version has arrived
if version != self.app_version:
@ -494,6 +494,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.SIGNAL(u'update_global_theme'), self.defaultThemeChanged)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'version_check'), self.versionCheck)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'blank_check'), self.blankCheck)
QtCore.QObject.connect(self.FileNewItem,
QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onNewService)
@ -583,6 +585,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.activateWindow()
if str_to_bool(self.generalConfig.get_config(u'auto open', False)):
self.ServiceManagerContents.onLoadService(True)
def blankCheck(self):
if str_to_bool(self.generalConfig.get_config(u'screen blank', False)) \
and str_to_bool(self.generalConfig.get_config(u'blank warning', False)):
self.LiveController.onBlankDisplay(True)

View File

@ -28,7 +28,6 @@ import logging
from PyQt4 import QtGui
from openlp.core.ui import GeneralTab, ThemesTab
from openlp.core.lib import Receiver
from settingsdialog import Ui_SettingsDialog
log = logging.getLogger(__name__)
@ -45,7 +44,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.ThemesTab = ThemesTab(mainWindow)
self.addTab(u'Themes', self.ThemesTab)
def addTab(self, name, tab):
def addTab(self, name, tab):
log.info(u'Adding %s tab' % tab.tabTitle)
self.SettingsTabWidget.addTab(tab, tab.tabTitleVisible)

View File

@ -403,14 +403,14 @@ class SlideController(QtGui.QWidget):
if self.songEdit:
slideno = self.selectedRow
self.songEdit = False
self.addServiceManagerItem(item, slideno)
self._processItem(item, slideno)
def replaceServiceManagerItem(self, item):
"""
Replacement item following a remote edit
"""
if item.__eq__(self.serviceItem):
self.addServiceManagerItem(item, self.PreviewListWidget.currentRow())
self._processItem(item, self.PreviewListWidget.currentRow())
def addServiceManagerItem(self, item, slideno):
"""
@ -419,27 +419,32 @@ class SlideController(QtGui.QWidget):
Called by ServiceManager
"""
log.debug(u'addServiceManagerItem')
#If old item was a command tell it to stop
if self.serviceItem and self.serviceItem.is_command():
self.onMediaStop()
if item.is_media():
self.onMediaStart(item)
elif item.is_command():
if self.isLive:
blanked = self.blankButton.isChecked()
else:
blanked = False
Receiver.send_message(u'%s_start' % item.name.lower(), \
[item.title, item.service_item_path,
item.get_frame_title(), slideno, self.isLive, blanked])
self.displayServiceManagerItems(item, slideno)
#If service item is the same as the current on only change slide
if item.__eq__(self.serviceItem):
self.PreviewListWidget.selectRow(slideno)
self.onSlideSelected()
return
self._processItem(item, slideno)
def displayServiceManagerItems(self, serviceItem, slideno):
def _processItem(self, serviceItem, slideno):
"""
Loads a ServiceItem into the system from ServiceManager
Display the slide number passed
"""
log.debug(u'displayServiceManagerItems Start')
log.debug(u'processsManagerItem')
#If old item was a command tell it to stop
if self.serviceItem and self.serviceItem.is_command():
self.onMediaStop()
if serviceItem.is_media():
self.onMediaStart(serviceItem)
elif serviceItem.is_command():
if self.isLive:
blanked = self.blankButton.isChecked()
else:
blanked = False
Receiver.send_message(u'%s_start' % serviceItem.name.lower(), \
[serviceItem.title, serviceItem.service_item_path,
serviceItem.get_frame_title(), slideno, self.isLive, blanked])
self.slideList = {}
width = self.parent.ControlSplitter.sizes()[self.split]
#Set pointing cursor when we have somthing to point at
@ -503,7 +508,6 @@ class SlideController(QtGui.QWidget):
log.log(15, u'Display Rendering took %4s' % (time.time() - before))
if self.isLive:
self.serviceItem.request_audit()
log.debug(u'displayServiceManagerItems End')
#Screen event methods
def onSlideSelectedFirst(self):

View File

@ -29,6 +29,8 @@ import logging
import urllib2
from datetime import datetime
import openlp
log = logging.getLogger(__name__)
class AppLocation(object):
@ -43,7 +45,7 @@ class AppLocation(object):
@staticmethod
def get_directory(dir_type):
if dir_type == AppLocation.AppDir:
return os.path.abspath(os.path.split(sys.argv[0])[0])
return os.path.abspath(os.path.split(sys.argv[0])[0])
elif dir_type == AppLocation.ConfigDir:
if os.getenv(u'PORTABLE') is not None:
path = os.path.split(os.path.abspath(sys.argv[0]))[0]
@ -77,11 +79,19 @@ class AppLocation(object):
path = os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')
return path
elif dir_type == AppLocation.PluginsDir:
plugin_path = None
app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
if hasattr(sys, u'frozen') and sys.frozen == 1:
return os.path.join(app_path, u'plugins')
if sys.platform == u'win32':
if hasattr(sys, u'frozen') and sys.frozen == 1:
plugin_path = os.path.join(app_path, u'plugins')
else:
plugin_path = os.path.join(app_path, u'openlp', u'plugins')
elif sys.platform == u'darwin':
plugin_path = os.path.join(app_path, u'plugins')
else:
return os.path.join(app_path, u'openlp', u'plugins')
plugin_path = os.path.join(
os.path.split(openlp.__file__)[0], u'plugins')
return plugin_path
def check_latest_version(config, current_version):

View File

@ -315,23 +315,23 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
def performImport(self):
bible_type = self.field(u'source_format').toInt()[0]
success = False
importer = None
if bible_type == BibleFormat.OSIS:
# Import an OSIS bible
success = self.manager.import_bible(BibleFormat.OSIS,
importer = self.manager.import_bible(BibleFormat.OSIS,
name=unicode(self.field(u'license_version').toString()),
filename=unicode(self.field(u'osis_location').toString())
)
elif bible_type == BibleFormat.CSV:
# Import a CSV bible
success = self.manager.import_bible(BibleFormat.CSV,
importer = self.manager.import_bible(BibleFormat.CSV,
name=unicode(self.field(u'license_version').toString()),
booksfile=self.field(u'csv_booksfile').toString(),
versefile=self.field(u'csv_versefile').toString()
)
elif bible_type == BibleFormat.OpenSong:
# Import an OpenSong bible
success = self.manager.import_bible(BibleFormat.OpenSong,
importer = self.manager.import_bible(BibleFormat.OpenSong,
name=unicode(self.field(u'license_version').toString()),
filename=self.field(u'opensong_file').toString()
)
@ -341,18 +341,19 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
download_location = self.field(u'web_location').toInt()[0]
if download_location == DownloadLocation.Crosswalk:
bible = self.web_bible_list[DownloadLocation.Crosswalk][
unicode(self.BibleComboBox.currentText())]
unicode(self.BibleComboBox.currentText(), u'utf8')]
elif download_location == DownloadLocation.BibleGateway:
bible = self.web_bible_list[DownloadLocation.BibleGateway][
unicode(self.BibleComboBox.currentText())]
success = self.manager.import_bible(BibleFormat.WebDownload,
name=unicode(self.field(u'license_version').toString()),
download_source=unicode(DownloadLocation.get_name(download_location)),
download_name=unicode(bible),
proxy_server=unicode(self.field(u'proxy_server').toString()),
proxy_username=unicode(self.field(u'proxy_username').toString()),
proxy_password=unicode(self.field(u'proxy_password').toString())
self.BibleComboBox.currentText()]
importer = self.manager.import_bible(BibleFormat.WebDownload,
name=unicode(self.field(u'license_version').toString(), u'utf8'),
download_source=DownloadLocation.get_name(download_location),
download_name=bible,
proxy_server=unicode(self.field(u'proxy_server').toString(), u'utf8'),
proxy_username=unicode(self.field(u'proxy_username').toString(), u'utf8'),
proxy_password=unicode(self.field(u'proxy_password').toString(), u'utf8')
)
success = importer.do_import()
if success:
self.manager.save_meta_data(
unicode(self.field(u'license_version').toString()),
@ -365,6 +366,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
else:
self.ImportProgressLabel.setText(
self.trUtf8('Your Bible import failed.'))
importer.delete()
def postImport(self):
self.ImportProgressBar.setValue(self.ImportProgressBar.maximum())

View File

@ -27,6 +27,7 @@ import urllib2
import logging
import re
import chardet
import htmlentitydefs
only_verses = re.compile(r'([\w .]+)[ ]+([0-9]+)[ ]*[:|v|V][ ]*([0-9]+)'
r'(?:[ ]*-[ ]*([0-9]+|end))?(?:[ ]*,[ ]*([0-9]+)(?:[ ]*-[ ]*([0-9]+|end))?)?',
@ -115,7 +116,6 @@ def parse_reference(reference):
log.debug(reference_list)
return reference_list
class SearchResults(object):
"""
Encapsulate a set of search results. This is Bible-type independant.
@ -247,3 +247,33 @@ class BibleCommon(object):
start_tag = text.find(u'<')
text = text.replace(u'>', u'')
return text.rstrip().lstrip()
def unescape(text):
"""
Removes HTML or XML character references and entities from a text string.
Courtesy of Fredrik Lundh, http://effbot.org/zone/re-sub.htm#unescape-html
@param text The HTML (or XML) source text.
@return The plain text, as a Unicode string, if necessary.
"""
def fixup(m):
text = m.group(0)
if text[:2] == u'&#':
# character reference
try:
if text[:3] == u'&#x':
return unichr(int(text[3:-1], 16))
else:
return unichr(int(text[2:-1]))
except ValueError:
pass
else:
# named entity
try:
text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
except KeyError:
pass
return text # leave as is
return re.sub(u'&#?\w+;', fixup, text)

View File

@ -26,6 +26,7 @@
import os
import logging
import chardet
import re
from sqlalchemy import or_
from PyQt4 import QtCore
@ -63,16 +64,21 @@ class BibleDB(QtCore.QObject):
QtCore.QObject.__init__(self)
if u'path' not in kwargs:
raise KeyError(u'Missing keyword argument "path".')
if u'name' not in kwargs:
raise KeyError(u'Missing keyword argument "name".')
if u'config' not in kwargs:
raise KeyError(u'Missing keyword argument "config".')
if u'name' not in kwargs and u'file' not in kwargs:
raise KeyError(u'Missing keyword argument "name" or "file".')
self.stop_import_flag = False
self.name = kwargs[u'name']
self.config = kwargs[u'config']
self.db_file = os.path.join(kwargs[u'path'],
u'%s.sqlite' % kwargs[u'name'])
log.debug(u'Load bible %s on path %s', kwargs[u'name'], self.db_file)
if u'name' in kwargs:
self.name = kwargs[u'name']
if not isinstance(self.name, unicode):
self.name = unicode(self.name, u'utf-8')
self.file = self.clean_filename(self.name)
if u'file' in kwargs:
self.file = kwargs[u'file']
self.db_file = os.path.join(kwargs[u'path'], self.file)
log.debug(u'Load bible %s on path %s', self.file, self.db_file)
db_type = self.config.get_config(u'db type', u'sqlite')
db_url = u''
if db_type == u'sqlite':
@ -85,12 +91,35 @@ class BibleDB(QtCore.QObject):
self.config.get_config(u'db database'))
self.metadata, self.session = init_models(db_url)
self.metadata.create_all(checkfirst=True)
if u'file' in kwargs:
self.get_name()
def get_name(self):
version_name = self.get_meta(u'Version')
if version_name:
self.name = version_name.value
else:
self.name = None
return self.name
def clean_filename(self, old_filename):
if not isinstance(old_filename, unicode):
old_filename = unicode(old_filename, u'utf-8')
old_filename = re.sub(r'[^\w]+', u'_', old_filename).strip(u'_')
return old_filename + u'.sqlite'
def delete(self):
try:
os.remove(self.db_file)
return True
except:
return False
def register(self, wizard):
"""
This method basically just initialialises the database. It is called
from the Bible Manager when a Bible is imported. Descendant classes
may want to override this method to supply their own custom
may want to override this method to suVersionpply their own custom
initialisation as well.
"""
self.wizard = wizard
@ -241,8 +270,6 @@ class BibleDB(QtCore.QObject):
count = self.session.query(Verse.chapter).join(Book)\
.filter(Book.name==book)\
.distinct().count()
#verse = self.session.query(Verse).join(Book).filter(
# Book.name == bookname).order_by(Verse.chapter.desc()).first()
if not count:
return 0
else:
@ -254,9 +281,6 @@ class BibleDB(QtCore.QObject):
.filter(Book.name==book)\
.filter(Verse.chapter==chapter)\
.count()
#verse = self.session.query(Verse).join(Book).filter(
# Book.name == bookname).filter(
# Verse.chapter == chapter).order_by(Verse.verse.desc()).first()
if not count:
return 0
else:

View File

@ -28,11 +28,11 @@ import urllib2
import os
import sqlite3
from BeautifulSoup import BeautifulSoup
from BeautifulSoup import BeautifulSoup, Tag, NavigableString
from openlp.core.lib import Receiver
from openlp.core.utils import AppLocation
from common import BibleCommon, SearchResults
from common import BibleCommon, SearchResults, unescape
from db import BibleDB
from openlp.plugins.bibles.lib.models import Book
@ -146,44 +146,63 @@ class BGExtract(BibleCommon):
urlstring = u'http://www.biblegateway.com/passage/?search=%s+%s' \
u'&version=%s' % (bookname, chapter, version)
log.debug(u'BibleGateway url = %s' % urlstring)
xml_string = self._get_web_text(urlstring, self.proxyurl)
verseSearch = u'<sup class=\"versenum'
verseFootnote = u'<sup class=\'footnote'
verse = 1
i = xml_string.find(u'result-text-style-normal') + 26
xml_string = xml_string[i:len(xml_string)]
versePos = xml_string.find(verseSearch)
bible = {}
while versePos > -1:
# clear out string
verseText = u''
versePos = xml_string.find(u'</sup>', versePos) + 6
i = xml_string.find(verseSearch, versePos + 1)
# Not sure if this is needed now
if i == -1:
i = xml_string.find(u'</div', versePos + 1)
j = xml_string.find(u'<strong', versePos + 1)
if j > 0 and j < i:
i = j
verseText = xml_string[versePos + 7 : i ]
# store the verse
bible[verse] = self._clean_text(verseText)
versePos = -1
else:
verseText = xml_string[versePos: i]
start_tag = verseText.find(verseFootnote)
while start_tag > -1:
end_tag = verseText.find(u'</sup>')
verseText = verseText[:start_tag] + verseText[end_tag + 6:len(verseText)]
start_tag = verseText.find(verseFootnote)
# Chop off verse and start again
xml_string = xml_string[i:]
#look for the next verse
versePos = xml_string.find(verseSearch)
# store the verse
bible[verse] = self._clean_text(verseText)
verse += 1
return SearchResults(bookname, chapter, bible)
# Let's get the page, and then open it in BeautifulSoup, so as to
# attempt to make "easy" work of bad HTML.
page = urllib2.urlopen(urlstring)
soup = BeautifulSoup(page)
verses = soup.find(u'div', u'result-text-style-normal')
verse_number = 0
verse_list = {0: u''}
# http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html
# This is a PERFECT example of opening the Cthulu tag!
# O Bible Gateway, why doth ye such horrific HTML produce?
for verse in verses:
if isinstance(verse, Tag) and verse.name == u'div' and filter(lambda a: a[0] == u'class', verse.attrs)[0][1] == u'footnotes':
break
if isinstance(verse, Tag) and verse.name == u'sup' and filter(lambda a: a[0] == u'class', verse.attrs)[0][1] != u'versenum':
continue
if isinstance(verse, Tag) and verse.name == u'p' and not verse.contents:
continue
if isinstance(verse, Tag) and (verse.name == u'p' or verse.name == u'font') and verse.contents:
for item in verse.contents:
if isinstance(item, Tag) and (item.name == u'h4' or item.name == u'h5'):
continue
if isinstance(item, Tag) and item.name == u'sup' and filter(lambda a: a[0] == u'class', item.attrs)[0][1] != u'versenum':
continue
if isinstance(item, Tag) and item.name == u'p' and not item.contents:
continue
if isinstance(item, Tag) and item.name == u'sup':
verse_number = int(str(item.contents[0]))
verse_list[verse_number] = u''
continue
if isinstance(item, Tag) and item.name == u'font':
for subitem in item.contents:
if isinstance(subitem, Tag) and subitem.name == u'sup' and filter(lambda a: a[0] == u'class', subitem.attrs)[0][1] != u'versenum':
continue
if isinstance(subitem, Tag) and subitem.name == u'p' and not subitem.contents:
continue
if isinstance(subitem, Tag) and subitem.name == u'sup':
verse_number = int(str(subitem.contents[0]))
verse_list[verse_number] = u''
continue
if isinstance(subitem, NavigableString):
verse_list[verse_number] = verse_list[verse_number] + subitem.replace(u'&nbsp;', u' ')
continue
if isinstance(item, NavigableString):
verse_list[verse_number] = verse_list[verse_number] + item.replace(u'&nbsp;', u' ')
continue
if isinstance(verse, Tag) and verse.name == u'sup':
verse_number = int(str(verse.contents[0]))
verse_list[verse_number] = u''
continue
if isinstance(verse, NavigableString):
verse_list[verse_number] = verse_list[verse_number] + \
unescape(unicode(verse, u'utf-8').replace(u'&nbsp;', u' '))
# Delete the "0" element, since we don't need it, it's just there for
# some stupid initial whitespace, courtesy of Bible Gateway.
del verse_list[0]
# Finally, return the list of verses in a "SearchResults" object.
return SearchResults(bookname, chapter, verse_list)
class CWExtract(BibleCommon):
log.info(u'%s CWExtract loaded', __name__)

View File

@ -24,7 +24,6 @@
###############################################################################
import logging
import os
from common import parse_reference
from opensong import OpenSongBible
@ -123,20 +122,21 @@ class BibleManager(object):
log.debug(u'Bible Files %s', files)
self.db_cache = {}
for filename in files:
name, extension = os.path.splitext(filename)
self.db_cache[name] = BibleDB(self.parent, path=self.path,
name=name, config=self.config)
bible = BibleDB(self.parent, path=self.path, file=filename,
config=self.config)
name = bible.get_name()
log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible
# look to see if lazy load bible exists and get create getter.
source = self.db_cache[name].get_meta(u'download source')
if source:
download_name = self.db_cache[name].get_meta(u'download name').value
meta_proxy = self.db_cache[name].get_meta(u'proxy url')
web_bible = HTTPBible(self.parent, path=self.path, name=name,
config=self.config, download_source=source.value,
download_name=download_name)
web_bible = HTTPBible(self.parent, path=self.path,
file=filename, config=self.config,
download_source=source.value, download_name=download_name)
if meta_proxy:
web_bible.set_proxy_server(meta_proxy.value)
#del self.db_cache[name]
self.db_cache[name] = web_bible
log.debug(u'Bibles reloaded')
@ -165,7 +165,7 @@ class BibleManager(object):
importer = class_(self.parent, **kwargs)
name = importer.register(self.import_wizard)
self.db_cache[name] = importer
return importer.do_import()
return importer
def get_bibles(self):
"""

View File

@ -65,6 +65,12 @@ class BibleMediaItem(MediaManagerItem):
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlpreloadbibles'), self.reloadBibles)
def _decodeQtObject(self, listobj, key):
obj = listobj[QtCore.QString(key)]
if isinstance(obj, QtCore.QVariant):
obj = obj.toPyObject()
return unicode(obj)
def initPluginNameVisible(self):
self.PluginNameVisible = self.trUtf8('Bible')
@ -452,15 +458,17 @@ class BibleMediaItem(MediaManagerItem):
# Let's loop through the main lot, and assemble our verses
for item in items:
bitem = self.ListView.item(item.row())
reference = bitem.data(QtCore.Qt.UserRole).toPyObject()
bible = unicode(reference[QtCore.QString('bible')].toPyObject())
book = unicode(reference[QtCore.QString('book')].toPyObject())
chapter = unicode(reference[QtCore.QString('chapter')].toPyObject())
verse = unicode(reference[QtCore.QString('verse')].toPyObject())
text = unicode(reference[QtCore.QString('text')].toPyObject())
version = unicode(reference[QtCore.QString('version')].toPyObject())
copyright = unicode(reference[QtCore.QString('copyright')].toPyObject())
permission = unicode(reference[QtCore.QString('permission')].toPyObject())
reference = bitem.data(QtCore.Qt.UserRole)
if isinstance(reference, QtCore.QVariant):
reference = reference.toPyObject()
bible = self._decodeQtObject(reference, 'bible')
book = self._decodeQtObject(reference, 'book')
chapter = self._decodeQtObject(reference, 'chapter')
verse = self._decodeQtObject(reference, 'verse')
text = self._decodeQtObject(reference, 'text')
version = self._decodeQtObject(reference, 'version')
copyright = self._decodeQtObject(reference, 'copyright')
permission = self._decodeQtObject(reference, 'permission')
if self.parent.settings_tab.display_style == 1:
verse_text = self.formatVerse(old_chapter, chapter, verse, u'(u', u')')
elif self.parent.settings_tab.display_style == 2:

View File

@ -114,12 +114,14 @@ class OSISBible(BibleDB):
osis = codecs.open(self.filename, u'r', details['encoding'])
last_chapter = 0
testament = 1
match_count = 0
db_book = None
for file_record in osis:
if self.stop_import_flag:
break
match = self.verse_regex.search(file_record)
if match:
match_count += 1
book = match.group(1)
chapter = int(match.group(2))
verse = int(match.group(3))
@ -166,6 +168,8 @@ class OSISBible(BibleDB):
Receiver.send_message(u'process_events')
self.commit()
self.wizard.incrementProgressBar(u'Finishing import...')
if match_count == 0:
success = False
except:
log.exception(u'Loading bible from OSIS file failed')
success = False

View File

@ -87,6 +87,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
def initialise(self):
self.editAll = False
self.AddButton.setEnabled(True)
self.DeleteButton.setEnabled(False)
self.EditButton.setEnabled(False)
self.EditAllButton.setEnabled(True)

View File

@ -1,3 +1,3 @@
hiddenimports = ['openlp.plugins.presentations.lib.impresscontroller',
hiddenimports = ['openlp.plugins.presentations.lib.impresscontroller',
'openlp.plugins.presentations.lib.powerpointcontroller',
'openlp.plugins.presentations.lib.pptviewcontroller']

View File

@ -1,4 +1,4 @@
hiddenimports = ['plugins.songs.songsplugin',
hiddenimports = ['plugins.songs.songsplugin',
'plugins.bibles.bibleplugin',
'plugins.presentations.presentationplugin',
'plugins.media.mediaplugin',