This commit is contained in:
Andreas Preikschat 2011-06-06 07:35:19 +02:00
commit 221b64a272
72 changed files with 3122 additions and 1075 deletions

7
documentation/manual.txt Normal file
View File

@ -0,0 +1,7 @@
OpenLP Manual
=============
If you're reading this file, you're probably looking for the OpenLP manual. The
manual is hosted online at http://manual.openlp.org/. If you want to help with
the manual, contact the OpenLP team via IRC in the #openlp.org channel on the
Freenode network.

View File

@ -133,6 +133,8 @@ class OpenLP(QtGui.QApplication):
u'general/update check', QtCore.QVariant(True)).toBool() u'general/update check', QtCore.QVariant(True)).toBool()
if update_check: if update_check:
VersionThread(self.mainWindow).start() VersionThread(self.mainWindow).start()
Receiver.send_message(u'maindisplay_blank_check')
self.mainWindow.appStartup()
DelayStartThread(self.mainWindow).start() DelayStartThread(self.mainWindow).start()
return self.exec_() return self.exec_()

View File

@ -32,8 +32,9 @@ import os
from PyQt4 import QtCore from PyQt4 import QtCore
from sqlalchemy import create_engine, MetaData from sqlalchemy import create_engine, MetaData
from sqlalchemy.exceptions import InvalidRequestError from sqlalchemy.exc import InvalidRequestError
from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.pool import NullPool
from openlp.core.utils import AppLocation, delete_file from openlp.core.utils import AppLocation, delete_file
@ -52,7 +53,7 @@ def init_db(url, auto_flush=True, auto_commit=False):
``auto_commit`` ``auto_commit``
Sets the commit behaviour of the session Sets the commit behaviour of the session
""" """
engine = create_engine(url) engine = create_engine(url, poolclass=NullPool)
metadata = MetaData(bind=engine) metadata = MetaData(bind=engine)
session = scoped_session(sessionmaker(autoflush=auto_flush, session = scoped_session(sessionmaker(autoflush=auto_flush,
autocommit=auto_commit, bind=engine)) autocommit=auto_commit, bind=engine))

View File

@ -47,7 +47,6 @@ class OpenLPDockWidget(QtGui.QDockWidget):
""" """
log.debug(u'Initialise the %s widget' % name) log.debug(u'Initialise the %s widget' % name)
QtGui.QDockWidget.__init__(self, parent) QtGui.QDockWidget.__init__(self, parent)
self.parent = parent
if name: if name:
self.setObjectName(name) self.setObjectName(name)
if icon: if icon:

View File

@ -90,11 +90,10 @@ class MediaManagerItem(QtGui.QWidget):
""" """
Constructor to create the media manager item. Constructor to create the media manager item.
""" """
QtGui.QWidget.__init__(self) QtGui.QWidget.__init__(self, parent)
self.parent = parent self.hide()
self.whitespace = re.compile(r'\W+', re.UNICODE) self.whitespace = re.compile(r'[\W_]+', re.UNICODE)
#TODO: plugin should not be the parent in future self.plugin = plugin
self.plugin = parent # plugin
visible_title = self.plugin.getString(StringContent.VisibleName) visible_title = self.plugin.getString(StringContent.VisibleName)
self.title = unicode(visible_title[u'title']) self.title = unicode(visible_title[u'title'])
self.settingsSection = self.plugin.name.lower() self.settingsSection = self.plugin.name.lower()
@ -112,13 +111,10 @@ class MediaManagerItem(QtGui.QWidget):
self.requiredIcons() self.requiredIcons()
self.setupUi() self.setupUi()
self.retranslateUi() self.retranslateUi()
self.autoSelectItem = None self.auto_select_id = -1
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_service_load' % self.parent.name.lower()), QtCore.SIGNAL(u'%s_service_load' % self.plugin.name.lower()),
self.serviceLoad) self.serviceLoad)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_set_autoselect_item' % self.parent.name.lower()),
self.setAutoSelectItem)
def requiredIcons(self): def requiredIcons(self):
""" """
@ -458,7 +454,8 @@ class MediaManagerItem(QtGui.QWidget):
""" """
if QtCore.QSettings().value(u'advanced/single click preview', if QtCore.QSettings().value(u'advanced/single click preview',
QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \ QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \
and self.listView.selectedIndexes(): and self.listView.selectedIndexes() \
and self.auto_select_id == -1:
self.onPreviewClick(True) self.onPreviewClick(True)
def onPreviewClick(self, keepFocus=False): def onPreviewClick(self, keepFocus=False):
@ -475,13 +472,10 @@ class MediaManagerItem(QtGui.QWidget):
serviceItem = self.buildServiceItem() serviceItem = self.buildServiceItem()
if serviceItem: if serviceItem:
serviceItem.from_plugin = True serviceItem.from_plugin = True
self.parent.previewController.addServiceItem(serviceItem) self.plugin.previewController.addServiceItem(serviceItem)
if keepFocus: if keepFocus:
self.listView.setFocus() self.listView.setFocus()
def setAutoSelectItem(self, itemToSelect=None):
self.autoSelectItem = itemToSelect
def onLiveClick(self): def onLiveClick(self):
""" """
Send an item live by building a service item then adding that service Send an item live by building a service item then adding that service
@ -503,7 +497,7 @@ class MediaManagerItem(QtGui.QWidget):
if serviceItem: if serviceItem:
if not item_id: if not item_id:
serviceItem.from_plugin = True serviceItem.from_plugin = True
self.parent.liveController.addServiceItem(serviceItem) self.plugin.liveController.addServiceItem(serviceItem)
def createItemFromId(self, item_id): def createItemFromId(self, item_id):
item = QtGui.QListWidgetItem() item = QtGui.QListWidgetItem()
@ -533,7 +527,7 @@ class MediaManagerItem(QtGui.QWidget):
serviceItem = self.buildServiceItem(item, True) serviceItem = self.buildServiceItem(item, True)
if serviceItem: if serviceItem:
serviceItem.from_plugin = False serviceItem.from_plugin = False
self.parent.serviceManager.addServiceItem(serviceItem, self.plugin.serviceManager.addServiceItem(serviceItem,
replace=replace) replace=replace)
def onAddEditClick(self): def onAddEditClick(self):
@ -546,14 +540,14 @@ class MediaManagerItem(QtGui.QWidget):
'You must select one or more items.')) 'You must select one or more items.'))
else: else:
log.debug(u'%s Add requested', self.plugin.name) log.debug(u'%s Add requested', self.plugin.name)
serviceItem = self.parent.serviceManager.getServiceItem() serviceItem = self.plugin.serviceManager.getServiceItem()
if not serviceItem: if not serviceItem:
QtGui.QMessageBox.information(self, UiStrings().NISs, QtGui.QMessageBox.information(self, UiStrings().NISs,
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'You must select an existing service item to add to.')) 'You must select an existing service item to add to.'))
elif self.plugin.name.lower() == serviceItem.name.lower(): elif self.plugin.name.lower() == serviceItem.name.lower():
self.generateSlideData(serviceItem) self.generateSlideData(serviceItem)
self.parent.serviceManager.addServiceItem(serviceItem, self.plugin.serviceManager.addServiceItem(serviceItem,
replace=True) replace=True)
else: else:
# Turn off the remote edit update message indicator # Turn off the remote edit update message indicator
@ -567,8 +561,8 @@ class MediaManagerItem(QtGui.QWidget):
""" """
Common method for generating a service item Common method for generating a service item
""" """
serviceItem = ServiceItem(self.parent) serviceItem = ServiceItem(self.plugin)
serviceItem.add_icon(self.parent.icon_path) serviceItem.add_icon(self.plugin.icon_path)
if self.generateSlideData(serviceItem, item, xmlVersion): if self.generateSlideData(serviceItem, item, xmlVersion):
return serviceItem return serviceItem
else: else:
@ -617,6 +611,16 @@ class MediaManagerItem(QtGui.QWidget):
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
return item_id return item_id
def save_auto_select_id(self):
"""
Sorts out, what item to select after loading a list.
"""
# The item to select has not been set.
if self.auto_select_id == -1:
item = self.listView.currentItem()
if item:
self.auto_select_id = item.data(QtCore.Qt.UserRole).toInt()[0]
def search(self, string): def search(self, string):
""" """
Performs a plugin specific search for items containing ``string`` Performs a plugin specific search for items containing ``string``

View File

@ -215,7 +215,8 @@ class Plugin(QtCore.QObject):
you need, and return it for integration into openlp.org. you need, and return it for integration into openlp.org.
""" """
if self.media_item_class: if self.media_item_class:
return self.media_item_class(self, self, self.icon) return self.media_item_class(self.mediadock.media_dock, self,
self.icon)
return None return None
def addImportMenuItem(self, importMenu): def addImportMenuItem(self, importMenu):
@ -299,6 +300,12 @@ class Plugin(QtCore.QObject):
if self.mediaItem: if self.mediaItem:
self.mediadock.remove_dock(self.mediaItem) self.mediadock.remove_dock(self.mediaItem)
def appStartup(self):
"""
Perform tasks on application starup
"""
pass
def usesTheme(self, theme): def usesTheme(self, theme):
""" """
Called to find out if a plugin is currently using a theme. Called to find out if a plugin is currently using a theme.

View File

@ -67,7 +67,7 @@ class Renderer(object):
``theme_manager`` ``theme_manager``
The ThemeManager instance, used to get the current theme details. The ThemeManager instance, used to get the current theme details.
""" """
log.debug(u'Initilisation started') log.debug(u'Initialisation started')
self.theme_manager = theme_manager self.theme_manager = theme_manager
self.image_manager = image_manager self.image_manager = image_manager
self.screens = ScreenList.get_instance() self.screens = ScreenList.get_instance()
@ -77,7 +77,7 @@ class Renderer(object):
self.theme_data = None self.theme_data = None
self.bg_frame = None self.bg_frame = None
self.force_page = False self.force_page = False
self.display = MainDisplay(self, self.image_manager, False) self.display = MainDisplay(None, self.image_manager, False)
self.display.setup() self.display.setup()
def update_display(self): def update_display(self):
@ -86,7 +86,7 @@ class Renderer(object):
""" """
log.debug(u'Update Display') log.debug(u'Update Display')
self._calculate_default(self.screens.current[u'size']) self._calculate_default(self.screens.current[u'size'])
self.display = MainDisplay(self, self.image_manager, False) self.display = MainDisplay(None, self.image_manager, False)
self.display.setup() self.display.setup()
self.bg_frame = None self.bg_frame = None
self.theme_data = None self.theme_data = None

View File

@ -147,6 +147,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
DisplayTags.remove_html_tag(self.selected) DisplayTags.remove_html_tag(self.selected)
self.selected = -1 self.selected = -1
self._resetTable() self._resetTable()
self._saveTable()
def onSavedPushed(self): def onSavedPushed(self):
""" """
@ -171,14 +172,19 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
html[u'end tag'] = u'{/%s}' % tag html[u'end tag'] = u'{/%s}' % tag
self.selected = -1 self.selected = -1
self._resetTable() self._resetTable()
temp = [] self._saveTable()
def _saveTable(self):
"""
Saves all display tags except protected ones.
"""
tags = []
for tag in DisplayTags.get_html_tags(): for tag in DisplayTags.get_html_tags():
if not tag[u'protected']: if not tag[u'protected']:
temp.append(tag) tags.append(tag)
if temp: if tags:
ctemp = cPickle.dumps(temp)
QtCore.QSettings().setValue(u'displayTags/html_tags', QtCore.QSettings().setValue(u'displayTags/html_tags',
QtCore.QVariant(ctemp)) QtCore.QVariant(cPickle.dumps(tags)))
else: else:
QtCore.QSettings().setValue(u'displayTags/html_tags', QtCore.QSettings().setValue(u'displayTags/html_tags',
QtCore.QVariant(u'')) QtCore.QVariant(u''))

View File

@ -106,7 +106,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
""" """
Saving exception log and system informations to a file. Saving exception log and system informations to a file.
""" """
report = unicode(translate('OpenLP.ExceptionForm', report_text = unicode(translate('OpenLP.ExceptionForm',
'**OpenLP Bug Report**\n' '**OpenLP Bug Report**\n'
'Version: %s\n\n' 'Version: %s\n\n'
'--- Details of the Exception. ---\n\n%s\n\n ' '--- Details of the Exception. ---\n\n%s\n\n '
@ -122,21 +122,21 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
filename = unicode(QtCore.QDir.toNativeSeparators(filename)) filename = unicode(QtCore.QDir.toNativeSeparators(filename))
SettingsManager.set_last_dir(self.settingsSection, os.path.dirname( SettingsManager.set_last_dir(self.settingsSection, os.path.dirname(
filename)) filename))
report = report % self._createReport() report_text = report_text % self._createReport()
try: try:
file = open(filename, u'w') report_file = open(filename, u'w')
try: try:
file.write(report) report_file.write(report_text)
except UnicodeError: except UnicodeError:
file.close() report_file.close()
file = open(filename, u'wb') report_file = open(filename, u'wb')
file.write(report.encode(u'utf-8')) report_file.write(report_text.encode(u'utf-8'))
finally: finally:
file.close() report_file.close()
except IOError: except IOError:
log.exception(u'Failed to write crash report') log.exception(u'Failed to write crash report')
finally: finally:
file.close() report_file.close()
def onSendReportButtonPressed(self): def onSendReportButtonPressed(self):
""" """

View File

@ -223,9 +223,9 @@ class GeneralTab(SettingsTab):
self.autoPreviewCheckBox.setText(translate('OpenLP.GeneralTab', self.autoPreviewCheckBox.setText(translate('OpenLP.GeneralTab',
'Automatically preview next item in service')) 'Automatically preview next item in service'))
self.enableLoopCheckBox.setText(translate('OpenLP.GeneralTab', self.enableLoopCheckBox.setText(translate('OpenLP.GeneralTab',
'Enable slide loop')) 'Enable slide wrap-around'))
self.timeoutLabel.setText(translate('OpenLP.GeneralTab', self.timeoutLabel.setText(translate('OpenLP.GeneralTab',
'Slide loop delay:')) 'Timed slide interval:'))
self.timeoutSpinBox.setSuffix(translate('OpenLP.GeneralTab', ' sec')) self.timeoutSpinBox.setSuffix(translate('OpenLP.GeneralTab', ' sec'))
self.ccliGroupBox.setTitle( self.ccliGroupBox.setTitle(
translate('OpenLP.GeneralTab', 'CCLI Details')) translate('OpenLP.GeneralTab', 'CCLI Details'))

View File

@ -49,8 +49,7 @@ class MainDisplay(QtGui.QGraphicsView):
This is the display screen. This is the display screen.
""" """
def __init__(self, parent, image_manager, live): def __init__(self, parent, image_manager, live):
QtGui.QGraphicsView.__init__(self) QtGui.QGraphicsView.__init__(self, parent)
self.parent = parent
self.isLive = live self.isLive = live
self.image_manager = image_manager self.image_manager = image_manager
self.screens = ScreenList.get_instance() self.screens = ScreenList.get_instance()
@ -149,7 +148,6 @@ class MainDisplay(QtGui.QGraphicsView):
self.__hideMouse() self.__hideMouse()
# To display or not to display? # To display or not to display?
if not self.screen[u'primary']: if not self.screen[u'primary']:
self.show()
self.primary = False self.primary = False
else: else:
self.primary = True self.primary = True

View File

@ -179,7 +179,7 @@ class Ui_MainWindow(object):
u'printServiceItem', [QtGui.QKeySequence(u'Ctrl+P')], u'printServiceItem', [QtGui.QKeySequence(u'Ctrl+P')],
self.serviceManagerContents.printServiceOrder, self.serviceManagerContents.printServiceOrder,
category=UiStrings().File) category=UiStrings().File)
self.fileExitItem = shortcut_action(mainWindow, u'FileExitItem', self.fileExitItem = shortcut_action(mainWindow, u'fileExitItem',
[QtGui.QKeySequence(u'Alt+F4')], mainWindow.close, [QtGui.QKeySequence(u'Alt+F4')], mainWindow.close,
u':/system/system_exit.png', category=UiStrings().File) u':/system/system_exit.png', category=UiStrings().File)
action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu)
@ -651,6 +651,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setViewMode(False, True, False, False, True) self.setViewMode(False, True, False, False, True)
self.modeLiveItem.setChecked(True) self.modeLiveItem.setChecked(True)
def appStartup(self):
# Give all the plugins a chance to perform some tasks at startup
Receiver.send_message(u'openlp_process_events')
for plugin in self.pluginManager.plugins:
if plugin.isActive():
Receiver.send_message(u'openlp_process_events')
plugin.appStartup()
Receiver.send_message(u'openlp_process_events')
def firstTime(self): def firstTime(self):
# Import themes if first time # Import themes if first time
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
@ -669,13 +678,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def blankCheck(self): def blankCheck(self):
""" """
Check and display message if screen blank on setup. Check and display message if screen blank on setup.
Triggered by delay thread.
""" """
settings = QtCore.QSettings() settings = QtCore.QSettings()
self.liveController.mainDisplaySetBackground()
if settings.value(u'%s/screen blank' % self.generalSettingsSection, if settings.value(u'%s/screen blank' % self.generalSettingsSection,
QtCore.QVariant(False)).toBool(): QtCore.QVariant(False)).toBool():
self.liveController.mainDisplaySetBackground() if settings.value(u'%s/blank warning' % self.generalSettingsSection,
if settings.value(u'blank warning',
QtCore.QVariant(False)).toBool(): QtCore.QVariant(False)).toBool():
QtGui.QMessageBox.question(self, QtGui.QMessageBox.question(self,
translate('OpenLP.MainWindow', translate('OpenLP.MainWindow',

View File

@ -40,7 +40,6 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.parent = parent
self.activePlugin = None self.activePlugin = None
self.programaticChange = False self.programaticChange = False
self.setupUi(self) self.setupUi(self)
@ -65,7 +64,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self._clearDetails() self._clearDetails()
self.programaticChange = True self.programaticChange = True
pluginListWidth = 0 pluginListWidth = 0
for plugin in self.parent.pluginManager.plugins: for plugin in self.parent().pluginManager.plugins:
item = QtGui.QListWidgetItem(self.pluginListWidget) item = QtGui.QListWidgetItem(self.pluginListWidget)
# We do this just to make 100% sure the status is an integer as # We do this just to make 100% sure the status is an integer as
# sometimes when it's loaded from the config, it isn't cast to int. # sometimes when it's loaded from the config, it isn't cast to int.
@ -117,7 +116,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
plugin_name_singular = \ plugin_name_singular = \
self.pluginListWidget.currentItem().text().split(u' ')[0] self.pluginListWidget.currentItem().text().split(u' ')[0]
self.activePlugin = None self.activePlugin = None
for plugin in self.parent.pluginManager.plugins: for plugin in self.parent().pluginManager.plugins:
if plugin.nameStrings[u'singular'] == plugin_name_singular: if plugin.nameStrings[u'singular'] == plugin_name_singular:
self.activePlugin = plugin self.activePlugin = plugin
break break
@ -133,6 +132,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
self.activePlugin.toggleStatus(PluginStatus.Active) self.activePlugin.toggleStatus(PluginStatus.Active)
Receiver.send_message(u'cursor_normal') Receiver.send_message(u'cursor_normal')
self.activePlugin.appStartup()
else: else:
self.activePlugin.toggleStatus(PluginStatus.Inactive) self.activePlugin.toggleStatus(PluginStatus.Inactive)
status_text = unicode( status_text = unicode(

View File

@ -56,7 +56,9 @@ http://doc.trolltech.com/4.7/richtext-html-subset.html#css-properties
font-size: large; font-size: large;
} }
.itemText {} .itemText {
margin-top: 10px;
}
.itemFooter { .itemFooter {
font-size: 8px; font-size: 8px;
@ -212,11 +214,11 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
verse_def = None verse_def = None
for slide in item.get_frames(): for slide in item.get_frames():
if not verse_def or verse_def != slide[u'verseTag']: if not verse_def or verse_def != slide[u'verseTag']:
p = self._addElement(u'div', parent=div, text_div = self._addElement(u'div', parent=div,
classId=u'itemText') classId=u'itemText')
else: else:
self._addElement(u'br', parent=p) self._addElement(u'br', parent=text_div)
self._addElement(u'p', slide[u'html'], p) self._addElement(u'span', slide[u'html'], text_div)
verse_def = slide[u'verseTag'] verse_def = slide[u'verseTag']
# Break the page before the div element. # Break the page before the div element.
if index != 0 and self.pageBreakAfterText.isChecked(): if index != 0 and self.pageBreakAfterText.isChecked():

View File

@ -79,7 +79,7 @@ class ScreenList(object):
``number`` ``number``
The number of the screen, which size has changed. The number of the screen, which size has changed.
""" """
log.info(u'screenResolutionChanged %d' % number) log.info(u'screen_resolution_changed %d' % number)
for screen in self.screen_list: for screen in self.screen_list:
if number == screen[u'number']: if number == screen[u'number']:
newScreen = { newScreen = {
@ -104,6 +104,9 @@ class ScreenList(object):
``changed_screen`` ``changed_screen``
The screen's number which has been (un)plugged. The screen's number which has been (un)plugged.
""" """
# Do not log at start up.
if changed_screen != -1:
log.info(u'screen_count_changed %d' % number)
# Remove unplugged screens. # Remove unplugged screens.
for screen in copy.deepcopy(self.screen_list): for screen in copy.deepcopy(self.screen_list):
if screen[u'number'] == self.desktop.numScreens(): if screen[u'number'] == self.desktop.numScreens():
@ -116,8 +119,7 @@ class ScreenList(object):
u'size': self.desktop.screenGeometry(number), u'size': self.desktop.screenGeometry(number),
u'primary': (self.desktop.primaryScreen() == number) u'primary': (self.desktop.primaryScreen() == number)
}) })
# We do not want to send this message, when the method is called the # We do not want to send this message at start up.
# first time.
if changed_screen != -1: if changed_screen != -1:
# Reload setting tabs to apply possible changes. # Reload setting tabs to apply possible changes.
Receiver.send_message(u'config_screen_changed') Receiver.send_message(u'config_screen_changed')
@ -241,6 +243,7 @@ class ScreenList(object):
height = settings.value(u'height', height = settings.value(u'height',
QtCore.QVariant(self.current[u'size'].height())).toInt()[0] QtCore.QVariant(self.current[u'size'].height())).toInt()[0]
self.override[u'size'] = QtCore.QRect(x, y, width, height) self.override[u'size'] = QtCore.QRect(x, y, width, height)
self.override[u'primary'] = False
settings.endGroup() settings.endGroup()
if override_display: if override_display:
self.set_override_display() self.set_override_display()

View File

@ -676,8 +676,18 @@ class ServiceManager(QtGui.QWidget):
.is_capable(ItemCapabilities.AllowsVariableStartTime): .is_capable(ItemCapabilities.AllowsVariableStartTime):
self.timeAction.setVisible(True) self.timeAction.setVisible(True)
self.themeMenu.menuAction().setVisible(False) self.themeMenu.menuAction().setVisible(False)
if serviceItem[u'service_item'].is_text(): # Set up the theme menu.
if serviceItem[u'service_item'].is_text() and \
self.mainwindow.renderer.theme_level == ThemeLevel.Song:
self.themeMenu.menuAction().setVisible(True) self.themeMenu.menuAction().setVisible(True)
# The service item does not have a theme, check the "Default".
if serviceItem[u'service_item'].theme is None:
themeAction = self.themeMenu.defaultAction()
else:
themeAction = self.themeMenu.findChild(
QtGui.QAction, serviceItem[u'service_item'].theme)
if themeAction is not None:
themeAction.setChecked(True)
action = self.menu.exec_(self.serviceManagerList.mapToGlobal(point)) action = self.menu.exec_(self.serviceManagerList.mapToGlobal(point))
def onServiceItemNoteForm(self): def onServiceItemNoteForm(self):
@ -949,6 +959,7 @@ class ServiceManager(QtGui.QWidget):
treewidgetitem.setToolTip(0, serviceitem.notes) treewidgetitem.setToolTip(0, serviceitem.notes)
treewidgetitem.setData(0, QtCore.Qt.UserRole, treewidgetitem.setData(0, QtCore.Qt.UserRole,
QtCore.QVariant(item[u'order'])) QtCore.QVariant(item[u'order']))
treewidgetitem.setSelected(item[u'selected'])
# Add the children to their parent treewidgetitem. # Add the children to their parent treewidgetitem.
for count, frame in enumerate(serviceitem.get_frames()): for count, frame in enumerate(serviceitem.get_frames()):
child = QtGui.QTreeWidgetItem(treewidgetitem) child = QtGui.QTreeWidgetItem(treewidgetitem)
@ -1020,16 +1031,34 @@ class ServiceManager(QtGui.QWidget):
# force reset of renderer as theme data has changed # force reset of renderer as theme data has changed
self.mainwindow.renderer.themedata = None self.mainwindow.renderer.themedata = None
if self.serviceItems: if self.serviceItems:
for item in self.serviceItems:
item[u'selected'] = False
serviceIterator = QtGui.QTreeWidgetItemIterator(
self.serviceManagerList)
while serviceIterator.value():
if serviceIterator.value().isSelected():
selectedItem = serviceIterator.value()
serviceIterator += 1
if selectedItem is not None:
if selectedItem.parent() is None:
pos = selectedItem.data(0, QtCore.Qt.UserRole).toInt()[0]
else:
pos = selectedItem.parent().data(0, QtCore.Qt.UserRole). \
toInt()[0]
self.serviceItems[pos - 1][u'selected'] = True
tempServiceItems = self.serviceItems tempServiceItems = self.serviceItems
self.serviceManagerList.clear() self.serviceManagerList.clear()
self.serviceItems = [] self.serviceItems = []
self.isNew = True self.isNew = True
for item in tempServiceItems: for item in tempServiceItems:
self.addServiceItem( self.addServiceItem(
item[u'service_item'], False, expand=item[u'expanded']) item[u'service_item'], False, expand=item[u'expanded'],
repaint=False, selected=item[u'selected'])
# Set to False as items may have changed rendering # Set to False as items may have changed rendering
# does not impact the saved song so True may also be valid # does not impact the saved song so True may also be valid
self.setModified() self.setModified()
# Repaint it once only at the end
self.repaintServiceList(-1, -1)
Receiver.send_message(u'cursor_normal') Receiver.send_message(u'cursor_normal')
def serviceItemUpdate(self, message): def serviceItemUpdate(self, message):
@ -1059,7 +1088,7 @@ class ServiceManager(QtGui.QWidget):
self.setModified() self.setModified()
def addServiceItem(self, item, rebuild=False, expand=None, replace=False, def addServiceItem(self, item, rebuild=False, expand=None, replace=False,
repaint=True): repaint=True, selected=False):
""" """
Add a Service item to the list Add a Service item to the list
@ -1087,17 +1116,17 @@ class ServiceManager(QtGui.QWidget):
for inditem in item: for inditem in item:
self.serviceItems.append({u'service_item': inditem, self.serviceItems.append({u'service_item': inditem,
u'order': len(self.serviceItems) + 1, u'order': len(self.serviceItems) + 1,
u'expanded': expand}) u'expanded': expand, u'selected': selected})
else: else:
self.serviceItems.append({u'service_item': item, self.serviceItems.append({u'service_item': item,
u'order': len(self.serviceItems) + 1, u'order': len(self.serviceItems) + 1,
u'expanded': expand}) u'expanded': expand, u'selected': selected})
if repaint: if repaint:
self.repaintServiceList(len(self.serviceItems) - 1, -1) self.repaintServiceList(len(self.serviceItems) - 1, -1)
else: else:
self.serviceItems.insert(self.dropPosition, self.serviceItems.insert(self.dropPosition,
{u'service_item': item, u'order': self.dropPosition, {u'service_item': item, u'order': self.dropPosition,
u'expanded': expand}) u'expanded': expand, u'selected': selected})
self.repaintServiceList(self.dropPosition, -1) self.repaintServiceList(self.dropPosition, -1)
# if rebuilding list make sure live is fixed. # if rebuilding list make sure live is fixed.
if rebuild: if rebuild:
@ -1280,16 +1309,33 @@ class ServiceManager(QtGui.QWidget):
self.themeComboBox.clear() self.themeComboBox.clear()
self.themeMenu.clear() self.themeMenu.clear()
self.themeComboBox.addItem(u'') self.themeComboBox.addItem(u'')
themeGroup = QtGui.QActionGroup(self.themeMenu)
themeGroup.setExclusive(True)
themeGroup.setObjectName(u'themeGroup')
# Create a "Default" theme, which allows the user to reset the item's
# theme to the service theme or global theme.
defaultTheme = context_menu_action(self.themeMenu, None,
UiStrings().Default, self.onThemeChangeAction)
defaultTheme.setCheckable(True)
self.themeMenu.setDefaultAction(defaultTheme)
themeGroup.addAction(defaultTheme)
context_menu_separator(self.themeMenu)
for theme in theme_list: for theme in theme_list:
self.themeComboBox.addItem(theme) self.themeComboBox.addItem(theme)
context_menu_action(self.themeMenu, None, theme, themeAction = context_menu_action(self.themeMenu, None, theme,
self.onThemeChangeAction) self.onThemeChangeAction)
themeAction.setObjectName(theme)
themeAction.setCheckable(True)
themeGroup.addAction(themeAction)
find_and_set_in_combo_box(self.themeComboBox, self.service_theme) find_and_set_in_combo_box(self.themeComboBox, self.service_theme)
self.mainwindow.renderer.set_service_theme(self.service_theme) self.mainwindow.renderer.set_service_theme(self.service_theme)
self.regenerateServiceItems() self.regenerateServiceItems()
def onThemeChangeAction(self): def onThemeChangeAction(self):
theme = unicode(self.sender().text()) theme = unicode(self.sender().objectName())
# No object name means that the "Default" theme is supposed to be used.
if not theme:
theme = None
item = self.findServiceItem()[0] item = self.findServiceItem()[0]
self.serviceItems[item][u'service_item'].theme = theme self.serviceItems[item][u'service_item'].theme = theme
self.regenerateServiceItems() self.regenerateServiceItems()

View File

@ -46,7 +46,6 @@ class SlideList(QtGui.QTableWidget):
""" """
def __init__(self, parent=None, name=None): def __init__(self, parent=None, name=None):
QtGui.QTableWidget.__init__(self, parent.controller) QtGui.QTableWidget.__init__(self, parent.controller)
self.parent = parent
class SlideController(QtGui.QWidget): class SlideController(QtGui.QWidget):
@ -60,13 +59,12 @@ class SlideController(QtGui.QWidget):
""" """
QtGui.QWidget.__init__(self, parent) QtGui.QWidget.__init__(self, parent)
self.isLive = isLive self.isLive = isLive
self.parent = parent
self.screens = ScreenList.get_instance() self.screens = ScreenList.get_instance()
self.ratio = float(self.screens.current[u'size'].width()) / \ self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height()) float(self.screens.current[u'size'].height())
self.image_manager = self.parent.image_manager self.image_manager = self.parent().image_manager
self.loopList = [ self.loopList = [
u'Start Loop', u'Play Slides Menu',
u'Loop Separator', u'Loop Separator',
u'Image SpinBox' u'Image SpinBox'
] ]
@ -140,19 +138,20 @@ class SlideController(QtGui.QWidget):
self.previousItem = self.toolbar.addToolbarButton( self.previousItem = self.toolbar.addToolbarButton(
translate('OpenLP.SlideController', 'Previous Slide'), translate('OpenLP.SlideController', 'Previous Slide'),
u':/slides/slide_previous.png', u':/slides/slide_previous.png',
translate('OpenLP.SlideController', 'Move to previous'), translate('OpenLP.SlideController', 'Move to previous.'),
self.onSlideSelectedPrevious, self.onSlideSelectedPrevious,
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp], shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
context=QtCore.Qt.WidgetWithChildrenShortcut) context=QtCore.Qt.WidgetWithChildrenShortcut)
self.nextItem = self.toolbar.addToolbarButton( self.nextItem = self.toolbar.addToolbarButton(
translate('OpenLP.SlideController', 'Next Slide'), translate('OpenLP.SlideController', 'Next Slide'),
u':/slides/slide_next.png', u':/slides/slide_next.png',
translate('OpenLP.SlideController', 'Move to next'), translate('OpenLP.SlideController', 'Move to next.'),
self.onSlideSelectedNext, self.onSlideSelectedNext,
shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown], shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
context=QtCore.Qt.WidgetWithChildrenShortcut) context=QtCore.Qt.WidgetWithChildrenShortcut)
self.toolbar.addToolbarSeparator(u'Close Separator') self.toolbar.addToolbarSeparator(u'Close Separator')
if self.isLive: if self.isLive:
# Hide Menu
self.hideMenu = QtGui.QToolButton(self.toolbar) self.hideMenu = QtGui.QToolButton(self.toolbar)
self.hideMenu.setText(translate('OpenLP.SlideController', 'Hide')) self.hideMenu.setText(translate('OpenLP.SlideController', 'Hide'))
self.hideMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup) self.hideMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
@ -180,65 +179,72 @@ class SlideController(QtGui.QWidget):
self.hideMenu.menu().addAction(self.themeScreen) self.hideMenu.menu().addAction(self.themeScreen)
self.hideMenu.menu().addAction(self.desktopScreen) self.hideMenu.menu().addAction(self.desktopScreen)
self.toolbar.addToolbarSeparator(u'Loop Separator') self.toolbar.addToolbarSeparator(u'Loop Separator')
startLoop = self.toolbar.addToolbarButton( # Play Slides Menu
# Does not need translating - control string. self.playSlidesMenu = QtGui.QToolButton(self.toolbar)
u'Start Loop', u':/media/media_time.png', self.playSlidesMenu.setText(translate('OpenLP.SlideController',
translate('OpenLP.SlideController', 'Start continuous loop'), 'Play Slides'))
self.onStartLoop) self.playSlidesMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
startLoop.setObjectName(u'startLoop') self.toolbar.addToolbarWidget(u'Play Slides Menu',
action_list = ActionList.get_instance() self.playSlidesMenu)
action_list.add_action(startLoop, UiStrings().LiveToolbar) self.playSlidesMenu.setMenu(QtGui.QMenu(
stopLoop = self.toolbar.addToolbarButton( translate('OpenLP.SlideController', 'Play Slides'),
# Does not need translating - control string. self.toolbar))
u'Stop Loop', u':/media/media_stop.png', self.playSlidesLoop = shortcut_action(self.playSlidesMenu,
translate('OpenLP.SlideController', 'Stop continuous loop'), u'playSlidesLoop', [], self.onPlaySlidesLoop,
self.onStopLoop) u':/media/media_time.png', False, UiStrings().LiveToolbar)
stopLoop.setObjectName(u'stopLoop') self.playSlidesLoop.setText(
action_list.add_action(stopLoop, UiStrings().LiveToolbar) translate('OpenLP.SlideController', 'Play Slides in Loop'))
self.toogleLoop = shortcut_action(self, u'toogleLoop', self.playSlidesOnce = shortcut_action(self.playSlidesMenu,
[QtGui.QKeySequence(u'L')], self.onToggleLoop, u'playSlidesOnce', [], self.onPlaySlidesOnce,
category=UiStrings().LiveToolbar) u':/media/media_time.png', False, UiStrings().LiveToolbar)
self.toogleLoop.setText(translate('OpenLP.SlideController', self.playSlidesOnce.setText(
'Start/Stop continuous loop')) translate('OpenLP.SlideController', 'Play Slides to End'))
self.addAction(self.toogleLoop) if QtCore.QSettings().value(self.parent().generalSettingsSection +
u'/enable slide loop', QtCore.QVariant(True)).toBool():
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
else:
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
self.playSlidesMenu.menu().addAction(self.playSlidesLoop)
self.playSlidesMenu.menu().addAction(self.playSlidesOnce)
# Loop Delay Spinbox
self.delaySpinBox = QtGui.QSpinBox() self.delaySpinBox = QtGui.QSpinBox()
self.delaySpinBox.setRange(1, 180) self.delaySpinBox.setRange(1, 180)
self.toolbar.addToolbarWidget(u'Image SpinBox', self.delaySpinBox) self.toolbar.addToolbarWidget(u'Image SpinBox', self.delaySpinBox)
self.delaySpinBox.setSuffix(UiStrings().Seconds) self.delaySpinBox.setSuffix(UiStrings().Seconds)
self.delaySpinBox.setToolTip(translate('OpenLP.SlideController', self.delaySpinBox.setToolTip(translate('OpenLP.SlideController',
'Delay between slides in seconds')) 'Delay between slides in seconds.'))
else: else:
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
# Does not need translating - control string. # Does not need translating - control string.
u'Go Live', u':/general/general_live.png', u'Go Live', u':/general/general_live.png',
translate('OpenLP.SlideController', 'Move to live'), translate('OpenLP.SlideController', 'Move to live.'),
self.onGoLive) self.onGoLive)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
# Does not need translating - control string. # Does not need translating - control string.
u'Add to Service', u':/general/general_add.png', u'Add to Service', u':/general/general_add.png',
translate('OpenLP.SlideController', 'Add to Service'), translate('OpenLP.SlideController', 'Add to Service.'),
self.onPreviewAddToService) self.onPreviewAddToService)
self.toolbar.addToolbarSeparator(u'Close Separator') self.toolbar.addToolbarSeparator(u'Close Separator')
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
# Does not need translating - control string. # Does not need translating - control string.
u'Edit Song', u':/general/general_edit.png', u'Edit Song', u':/general/general_edit.png',
translate('OpenLP.SlideController', translate('OpenLP.SlideController',
'Edit and reload song preview'), 'Edit and reload song preview.'),
self.onEditSong) self.onEditSong)
self.controllerLayout.addWidget(self.toolbar) self.controllerLayout.addWidget(self.toolbar)
# Build a Media ToolBar # Build a Media ToolBar
self.mediabar = OpenLPToolbar(self) self.mediabar = OpenLPToolbar(self)
self.mediabar.addToolbarButton( self.mediabar.addToolbarButton(
u'Media Start', u':/slides/media_playback_start.png', u'Media Start', u':/slides/media_playback_start.png',
translate('OpenLP.SlideController', 'Start playing media'), translate('OpenLP.SlideController', 'Start playing media.'),
self.onMediaPlay) self.onMediaPlay)
self.mediabar.addToolbarButton( self.mediabar.addToolbarButton(
u'Media Pause', u':/slides/media_playback_pause.png', u'Media Pause', u':/slides/media_playback_pause.png',
translate('OpenLP.SlideController', 'Start playing media'), translate('OpenLP.SlideController', 'Start playing media.'),
self.onMediaPause) self.onMediaPause)
self.mediabar.addToolbarButton( self.mediabar.addToolbarButton(
u'Media Stop', u':/slides/media_playback_stop.png', u'Media Stop', u':/slides/media_playback_stop.png',
translate('OpenLP.SlideController', 'Start playing media'), translate('OpenLP.SlideController', 'Start playing media.'),
self.onMediaStop) self.onMediaStop)
if self.isLive: if self.isLive:
# Build the Song Toolbar # Build the Song Toolbar
@ -321,7 +327,6 @@ class SlideController(QtGui.QWidget):
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'), QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
self.receiveSpinDelay) self.receiveSpinDelay)
self.toolbar.makeWidgetsInvisible(self.loopList) self.toolbar.makeWidgetsInvisible(self.loopList)
self.toolbar.actions[u'Stop Loop'].setVisible(False)
else: else:
QtCore.QObject.connect(self.previewListWidget, QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
@ -461,7 +466,7 @@ class SlideController(QtGui.QWidget):
self.previewListWidget.resizeRowsToContents() self.previewListWidget.resizeRowsToContents()
else: else:
# Sort out image heights. # Sort out image heights.
width = self.parent.controlSplitter.sizes()[self.split] width = self.parent().controlSplitter.sizes()[self.split]
for framenumber in range(len(self.serviceItem.get_frames())): for framenumber in range(len(self.serviceItem.get_frames())):
self.previewListWidget.setRowHeight( self.previewListWidget.setRowHeight(
framenumber, width / self.ratio) framenumber, width / self.ratio)
@ -496,21 +501,14 @@ class SlideController(QtGui.QWidget):
self.mediabar.setVisible(False) self.mediabar.setVisible(False)
self.toolbar.makeWidgetsInvisible([u'Song Menu']) self.toolbar.makeWidgetsInvisible([u'Song Menu'])
self.toolbar.makeWidgetsInvisible(self.loopList) self.toolbar.makeWidgetsInvisible(self.loopList)
self.toogleLoop.setEnabled(False)
self.toolbar.actions[u'Start Loop'].setEnabled(False)
self.toolbar.actions[u'Stop Loop'].setEnabled(False)
self.toolbar.actions[u'Stop Loop'].setVisible(False)
if item.is_text(): if item.is_text():
if QtCore.QSettings().value( if QtCore.QSettings().value(
self.parent.songsSettingsSection + u'/display songbar', self.parent().songsSettingsSection + u'/display songbar',
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0: QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
self.toolbar.makeWidgetsVisible([u'Song Menu']) self.toolbar.makeWidgetsVisible([u'Song Menu'])
if item.is_capable(ItemCapabilities.AllowsLoop) and \ if item.is_capable(ItemCapabilities.AllowsLoop) and \
len(item.get_frames()) > 1: len(item.get_frames()) > 1:
self.toolbar.makeWidgetsVisible(self.loopList) self.toolbar.makeWidgetsVisible(self.loopList)
self.toogleLoop.setEnabled(True)
self.toolbar.actions[u'Start Loop'].setEnabled(True)
self.toolbar.actions[u'Stop Loop'].setEnabled(True)
if item.is_media(): if item.is_media():
self.toolbar.setVisible(False) self.toolbar.setVisible(False)
self.mediabar.setVisible(True) self.mediabar.setVisible(True)
@ -591,7 +589,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_start' % serviceItem.name.lower(), Receiver.send_message(u'%s_start' % serviceItem.name.lower(),
[serviceItem, self.isLive, self.hideMode(), slideno]) [serviceItem, self.isLive, self.hideMode(), slideno])
self.slideList = {} self.slideList = {}
width = self.parent.controlSplitter.sizes()[self.split] width = self.parent().controlSplitter.sizes()[self.split]
self.previewListWidget.clear() self.previewListWidget.clear()
self.previewListWidget.setRowCount(0) self.previewListWidget.setRowCount(0)
self.previewListWidget.setColumnWidth(0, width) self.previewListWidget.setColumnWidth(0, width)
@ -625,8 +623,8 @@ class SlideController(QtGui.QWidget):
label.setScaledContents(True) label.setScaledContents(True)
if self.serviceItem.is_command(): if self.serviceItem.is_command():
image = resize_image(frame[u'image'], image = resize_image(frame[u'image'],
self.parent.renderer.width, self.parent().renderer.width,
self.parent.renderer.height) self.parent().renderer.height)
else: else:
# If current slide set background to image # If current slide set background to image
if framenumber == slideno: if framenumber == slideno:
@ -635,7 +633,7 @@ class SlideController(QtGui.QWidget):
image = self.image_manager.get_image(frame[u'title']) image = self.image_manager.get_image(frame[u'title'])
label.setPixmap(QtGui.QPixmap.fromImage(image)) label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label) self.previewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * self.parent.renderer.screen_ratio slideHeight = width * self.parent().renderer.screen_ratio
row += 1 row += 1
text.append(unicode(row)) text.append(unicode(row))
self.previewListWidget.setItem(framenumber, 0, item) self.previewListWidget.setItem(framenumber, 0, item)
@ -736,7 +734,7 @@ class SlideController(QtGui.QWidget):
""" """
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive) log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
display_type = QtCore.QSettings().value( display_type = QtCore.QSettings().value(
self.parent.generalSettingsSection + u'/screen blank', self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'')).toString() QtCore.QVariant(u'')).toString()
if not self.display.primary: if not self.display.primary:
# Order done to handle initial conversion # Order done to handle initial conversion
@ -744,8 +742,10 @@ class SlideController(QtGui.QWidget):
self.onThemeDisplay(True) self.onThemeDisplay(True)
elif display_type == u'hidden': elif display_type == u'hidden':
self.onHideDisplay(True) self.onHideDisplay(True)
else: elif display_type == u'blanked':
self.onBlankDisplay(True) self.onBlankDisplay(True)
else:
Receiver.send_message(u'maindisplay_show')
def onSlideBlank(self): def onSlideBlank(self):
""" """
@ -772,11 +772,11 @@ class SlideController(QtGui.QWidget):
self.desktopScreen.setChecked(False) self.desktopScreen.setChecked(False)
if checked: if checked:
QtCore.QSettings().setValue( QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank', self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'blanked')) QtCore.QVariant(u'blanked'))
else: else:
QtCore.QSettings().remove( QtCore.QSettings().remove(
self.parent.generalSettingsSection + u'/screen blank') self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin() self.blankPlugin()
self.updatePreview() self.updatePreview()
@ -793,11 +793,11 @@ class SlideController(QtGui.QWidget):
self.desktopScreen.setChecked(False) self.desktopScreen.setChecked(False)
if checked: if checked:
QtCore.QSettings().setValue( QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank', self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'themed')) QtCore.QVariant(u'themed'))
else: else:
QtCore.QSettings().remove( QtCore.QSettings().remove(
self.parent.generalSettingsSection + u'/screen blank') self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin() self.blankPlugin()
self.updatePreview() self.updatePreview()
@ -814,11 +814,11 @@ class SlideController(QtGui.QWidget):
self.desktopScreen.setChecked(checked) self.desktopScreen.setChecked(checked)
if checked: if checked:
QtCore.QSettings().setValue( QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank', self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'hidden')) QtCore.QVariant(u'hidden'))
else: else:
QtCore.QSettings().remove( QtCore.QSettings().remove(
self.parent.generalSettingsSection + u'/screen blank') self.parent().generalSettingsSection + u'/screen blank')
self.hidePlugin(checked) self.hidePlugin(checked)
self.updatePreview() self.updatePreview()
@ -841,6 +841,11 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_unblank' Receiver.send_message(u'%s_unblank'
% self.serviceItem.name.lower(), % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive]) [self.serviceItem, self.isLive])
else:
if hide_mode:
Receiver.send_message(u'maindisplay_hide', hide_mode)
else:
Receiver.send_message(u'maindisplay_show')
def hidePlugin(self, hide): def hidePlugin(self, hide):
""" """
@ -859,6 +864,11 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_unblank' Receiver.send_message(u'%s_unblank'
% self.serviceItem.name.lower(), % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive]) [self.serviceItem, self.isLive])
else:
if hide:
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
else:
Receiver.send_message(u'maindisplay_show')
def onSlideSelected(self, start=False): def onSlideSelected(self, start=False):
""" """
@ -933,7 +943,7 @@ class SlideController(QtGui.QWidget):
rect.y(), rect.width(), rect.height()) rect.y(), rect.width(), rect.height())
self.slidePreview.setPixmap(winimg) self.slidePreview.setPixmap(winimg)
def onSlideSelectedNext(self): def onSlideSelectedNext(self, wrap=None):
""" """
Go to the next slide. Go to the next slide.
""" """
@ -946,8 +956,11 @@ class SlideController(QtGui.QWidget):
else: else:
row = self.previewListWidget.currentRow() + 1 row = self.previewListWidget.currentRow() + 1
if row == self.previewListWidget.rowCount(): if row == self.previewListWidget.rowCount():
if QtCore.QSettings().value(self.parent.generalSettingsSection + if wrap is None:
u'/enable slide loop', QtCore.QVariant(True)).toBool(): wrap = QtCore.QSettings().value(
self.parent().generalSettingsSection +
u'/enable slide loop', QtCore.QVariant(True)).toBool()
if wrap:
row = 0 row = 0
else: else:
row = self.previewListWidget.rowCount() - 1 row = self.previewListWidget.rowCount() - 1
@ -967,8 +980,8 @@ class SlideController(QtGui.QWidget):
else: else:
row = self.previewListWidget.currentRow() - 1 row = self.previewListWidget.currentRow() - 1
if row == -1: if row == -1:
if QtCore.QSettings().value(self.parent.generalSettingsSection + if QtCore.QSettings().value(self.parent().generalSettingsSection
u'/enable slide loop', QtCore.QVariant(True)).toBool(): + u'/enable slide loop', QtCore.QVariant(True)).toBool():
row = self.previewListWidget.rowCount() - 1 row = self.previewListWidget.rowCount() - 1
else: else:
row = 0 row = 0
@ -996,11 +1009,11 @@ class SlideController(QtGui.QWidget):
self.previewListWidget.rowCount() - 1) self.previewListWidget.rowCount() - 1)
self.slideSelected() self.slideSelected()
def onToggleLoop(self, toggled): def onToggleLoop(self):
""" """
Toggles the loop state. Toggles the loop state.
""" """
if self.toolbar.actions[u'Start Loop'].isVisible(): if self.playSlidesLoop.isChecked() or self.playSlidesOnce.isChecked():
self.onStartLoop() self.onStartLoop()
else: else:
self.onStopLoop() self.onStopLoop()
@ -1012,8 +1025,6 @@ class SlideController(QtGui.QWidget):
if self.previewListWidget.rowCount() > 1: if self.previewListWidget.rowCount() > 1:
self.timer_id = self.startTimer( self.timer_id = self.startTimer(
int(self.delaySpinBox.value()) * 1000) int(self.delaySpinBox.value()) * 1000)
self.toolbar.actions[u'Stop Loop'].setVisible(True)
self.toolbar.actions[u'Start Loop'].setVisible(False)
def onStopLoop(self): def onStopLoop(self):
""" """
@ -1022,15 +1033,39 @@ class SlideController(QtGui.QWidget):
if self.timer_id != 0: if self.timer_id != 0:
self.killTimer(self.timer_id) self.killTimer(self.timer_id)
self.timer_id = 0 self.timer_id = 0
self.toolbar.actions[u'Start Loop'].setVisible(True)
self.toolbar.actions[u'Stop Loop'].setVisible(False) def onPlaySlidesLoop(self, checked=None):
"""
Start or stop 'Play Slides in Loop'
"""
if checked is None:
checked = self.playSlidesLoop.isChecked()
else:
self.playSlidesLoop.setChecked(checked)
log.debug(u'onPlaySlidesLoop %s' % checked)
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
self.playSlidesOnce.setChecked(False)
self.onToggleLoop()
def onPlaySlidesOnce(self, checked=None):
"""
Start or stop 'Play Slides to End'
"""
if checked is None:
checked = self.playSlidesOnce.isChecked()
else:
self.playSlidesOnce.setChecked(checked)
log.debug(u'onPlaySlidesOnce %s' % checked)
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
self.playSlidesLoop.setChecked(False)
self.onToggleLoop()
def timerEvent(self, event): def timerEvent(self, event):
""" """
If the timer event is for this window select next slide If the timer event is for this window select next slide
""" """
if event.timerId() == self.timer_id: if event.timerId() == self.timer_id:
self.onSlideSelectedNext() self.onSlideSelectedNext(self.playSlidesLoop.isChecked())
def onEditSong(self): def onEditSong(self):
""" """
@ -1044,7 +1079,9 @@ class SlideController(QtGui.QWidget):
""" """
From the preview display request the Item to be added to service From the preview display request the Item to be added to service
""" """
self.parent.serviceManagerContents.addServiceItem(self.serviceItem) if self.serviceItem:
self.parent().serviceManagerContents.addServiceItem(
self.serviceItem)
def onGoLiveClick(self): def onGoLiveClick(self):
""" """
@ -1072,7 +1109,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message('servicemanager_preview_live', Receiver.send_message('servicemanager_preview_live',
u'%s:%s' % (self.serviceItem._uuid, row)) u'%s:%s' % (self.serviceItem._uuid, row))
else: else:
self.parent.liveController.addServiceManagerItem( self.parent().liveController.addServiceManagerItem(
self.serviceItem, row) self.serviceItem, row)
def onMediaStart(self, item): def onMediaStart(self, item):

View File

@ -57,8 +57,6 @@ class ThemeManager(QtGui.QWidget):
self.settingsSection = u'themes' self.settingsSection = u'themes'
self.themeForm = ThemeForm(self) self.themeForm = ThemeForm(self)
self.fileRenameForm = FileRenameForm(self) self.fileRenameForm = FileRenameForm(self)
self.serviceComboBox = \
self.mainwindow.serviceManagerContents.themeComboBox
# start with the layout # start with the layout
self.layout = QtGui.QVBoxLayout(self) self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0) self.layout.setSpacing(0)

View File

@ -145,10 +145,8 @@ class ThemesTab(SettingsTab):
def save(self): def save(self):
settings = QtCore.QSettings() settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
settings.setValue(u'theme level', settings.setValue(u'theme level', QtCore.QVariant(self.theme_level))
QtCore.QVariant(self.theme_level)) settings.setValue(u'global theme', QtCore.QVariant(self.global_theme))
settings.setValue(u'global theme',
QtCore.QVariant(self.global_theme))
settings.endGroup() settings.endGroup()
self.mainwindow.renderer.set_global_theme( self.mainwindow.renderer.set_global_theme(
self.global_theme, self.theme_level) self.global_theme, self.theme_level)
@ -186,8 +184,7 @@ class ThemesTab(SettingsTab):
self.settingsSection + u'/global theme', self.settingsSection + u'/global theme',
QtCore.QVariant(u'')).toString()) QtCore.QVariant(u'')).toString())
self.DefaultComboBox.clear() self.DefaultComboBox.clear()
for theme in theme_list: self.DefaultComboBox.addItems(theme_list)
self.DefaultComboBox.addItem(theme)
find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme) find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
self.mainwindow.renderer.set_global_theme( self.mainwindow.renderer.set_global_theme(
self.global_theme, self.theme_level) self.global_theme, self.theme_level)

View File

@ -69,7 +69,6 @@ class VersionThread(QtCore.QThread):
Run the thread. Run the thread.
""" """
time.sleep(1) time.sleep(1)
Receiver.send_message(u'maindisplay_blank_check')
app_version = get_application_version() app_version = get_application_version()
version = check_latest_version(app_version) version = check_latest_version(app_version)
remote_version = {} remote_version = {}

View File

@ -77,6 +77,8 @@ class LanguageManager(object):
AppLocation.LanguageDir)) AppLocation.LanguageDir))
file_names = trans_dir.entryList(QtCore.QStringList(u'*.qm'), file_names = trans_dir.entryList(QtCore.QStringList(u'*.qm'),
QtCore.QDir.Files, QtCore.QDir.Name) QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt_".
file_names = file_names.filter(QtCore.QRegExp("^(?!qt_)"))
for name in file_names: for name in file_names:
file_names.replaceInStrings(name, trans_dir.filePath(name)) file_names.replaceInStrings(name, trans_dir.filePath(name))
return file_names return file_names

View File

@ -41,7 +41,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
Initialise the alert form Initialise the alert form
""" """
self.manager = plugin.manager self.manager = plugin.manager
self.parent = plugin self.plugin = plugin
self.item_id = None self.item_id = None
QtGui.QDialog.__init__(self, plugin.formparent) QtGui.QDialog.__init__(self, plugin.formparent)
self.setupUi(self) self.setupUi(self)
@ -195,7 +195,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.parameterEdit.setFocus() self.parameterEdit.setFocus()
return False return False
text = text.replace(u'<>', unicode(self.parameterEdit.text())) text = text.replace(u'<>', unicode(self.parameterEdit.text()))
self.parent.alertsmanager.displayAlert(text) self.plugin.alertsmanager.displayAlert(text)
return True return True
def onCurrentRowChanged(self, row): def onCurrentRowChanged(self, row):

View File

@ -40,8 +40,7 @@ class AlertsManager(QtCore.QObject):
log.info(u'Alert Manager loaded') log.info(u'Alert Manager loaded')
def __init__(self, parent): def __init__(self, parent):
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self, parent)
self.parent = parent
self.screen = None self.screen = None
self.timer_id = 0 self.timer_id = 0
self.alertList = [] self.alertList = []
@ -85,8 +84,8 @@ class AlertsManager(QtCore.QObject):
if len(self.alertList) == 0: if len(self.alertList) == 0:
return return
text = self.alertList.pop(0) text = self.alertList.pop(0)
alertTab = self.parent.settings_tab alertTab = self.parent().settings_tab
self.parent.liveController.display.alert(text) self.parent().liveController.display.alert(text)
# Check to see if we have a timer running. # Check to see if we have a timer running.
if self.timer_id == 0: if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000) self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
@ -101,7 +100,7 @@ class AlertsManager(QtCore.QObject):
""" """
log.debug(u'timer event') log.debug(u'timer event')
if event.timerId() == self.timer_id: if event.timerId() == self.timer_id:
self.parent.liveController.display.alert(u'') self.parent().liveController.display.alert(u'')
self.killTimer(self.timer_id) self.killTimer(self.timer_id)
self.timer_id = 0 self.timer_id = 0
self.generateAlert() self.generateAlert()

View File

@ -33,6 +33,7 @@ from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import base_action, UiStrings from openlp.core.lib.ui import base_action, UiStrings
from openlp.core.utils.actions import ActionList from openlp.core.utils.actions import ActionList
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
from openlp.plugins.bibles.forms import BibleUpgradeForm
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -59,6 +60,8 @@ class BiblePlugin(Plugin):
#action_list.add_action(self.exportBibleItem, UiStrings().Export) #action_list.add_action(self.exportBibleItem, UiStrings().Export)
# Set to invisible until we can export bibles # Set to invisible until we can export bibles
self.exportBibleItem.setVisible(False) self.exportBibleItem.setVisible(False)
if len(self.manager.old_bible_databases):
self.toolsUpgradeItem.setVisible(True)
def finalise(self): def finalise(self):
""" """
@ -73,6 +76,19 @@ class BiblePlugin(Plugin):
#action_list.remove_action(self.exportBibleItem, UiStrings().Export) #action_list.remove_action(self.exportBibleItem, UiStrings().Export)
self.exportBibleItem.setVisible(False) self.exportBibleItem.setVisible(False)
def appStartup(self):
"""
Perform tasks on application starup
"""
if len(self.manager.old_bible_databases):
if QtGui.QMessageBox.information(self.formparent,
translate('OpenLP', 'Information'), translate('OpenLP',
'Bible format has changed.\nYou have to upgrade your '
'existing Bibles.\nShould OpenLP upgrade now?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes:
self.onToolsUpgradeItemTriggered()
def addImportMenuItem(self, import_menu): def addImportMenuItem(self, import_menu):
self.importBibleItem = base_action(import_menu, u'importBibleItem') self.importBibleItem = base_action(import_menu, u'importBibleItem')
self.importBibleItem.setText(translate('BiblesPlugin', '&Bible')) self.importBibleItem.setText(translate('BiblesPlugin', '&Bible'))
@ -88,6 +104,39 @@ class BiblePlugin(Plugin):
export_menu.addAction(self.exportBibleItem) export_menu.addAction(self.exportBibleItem)
self.exportBibleItem.setVisible(False) self.exportBibleItem.setVisible(False)
def addToolsMenuItem(self, tools_menu):
"""
Give the bible plugin the opportunity to add items to the
**Tools** menu.
``tools_menu``
The actual **Tools** menu item, so that your actions can
use it as their parent.
"""
log.debug(u'add tools menu')
self.toolsUpgradeItem = QtGui.QAction(tools_menu)
self.toolsUpgradeItem.setObjectName(u'toolsUpgradeItem')
self.toolsUpgradeItem.setText(
translate('BiblePlugin', '&Upgrade older Bibles'))
self.toolsUpgradeItem.setStatusTip(
translate('BiblePlugin', 'Upgrade the Bible databases to the '
'latest format'))
tools_menu.addAction(self.toolsUpgradeItem)
QtCore.QObject.connect(self.toolsUpgradeItem,
QtCore.SIGNAL(u'triggered()'), self.onToolsUpgradeItemTriggered)
self.toolsUpgradeItem.setVisible(False)
def onToolsUpgradeItemTriggered(self):
"""
Upgrade older bible databases.
"""
if not hasattr(self, u'upgrade_wizard'):
self.upgrade_wizard = BibleUpgradeForm(self.formparent,
self.manager, self)
# If the import was not cancelled then reload.
if self.upgrade_wizard.exec_():
self.mediaItem.reloadBibles()
def onBibleImportClick(self): def onBibleImportClick(self):
if self.mediaItem: if self.mediaItem:
self.mediaItem.onImportClick() self.mediaItem.onImportClick()
@ -149,4 +198,3 @@ class BiblePlugin(Plugin):
'Add the selected Bible to the service.') 'Add the selected Bible to the service.')
} }
self.setPluginUiTextStrings(tooltips) self.setPluginUiTextStrings(tooltips)

View File

@ -51,7 +51,10 @@ This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
them separate from the functionality, so that it is easier to recreate the GUI them separate from the functionality, so that it is easier to recreate the GUI
from the .ui files later if necessary. from the .ui files later if necessary.
""" """
from booknameform import BookNameForm
from languageform import LanguageForm
from bibleimportform import BibleImportForm from bibleimportform import BibleImportForm
from bibleupgradeform import BibleUpgradeForm
__all__ = ['BibleImportForm'] __all__ = [u'BookNameForm', u'LanguageForm', u'BibleImportForm',
u'BibleUpgradeForm']

View File

@ -41,6 +41,7 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import AppLocation, string_is_unicode from openlp.core.utils import AppLocation, string_is_unicode
from openlp.plugins.bibles.lib.manager import BibleFormat from openlp.plugins.bibles.lib.manager import BibleFormat
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -125,9 +126,6 @@ class BibleImportForm(OpenLPWizard):
QtCore.QObject.connect(self.osisBrowseButton, QtCore.QObject.connect(self.osisBrowseButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onOsisBrowseButtonClicked) self.onOsisBrowseButtonClicked)
QtCore.QObject.connect(self.csvTestamentsButton,
QtCore.SIGNAL(u'clicked()'),
self.onCsvTestamentsBrowseButtonClicked)
QtCore.QObject.connect(self.csvBooksButton, QtCore.QObject.connect(self.csvBooksButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onCsvBooksBrowseButtonClicked) self.onCsvBooksBrowseButtonClicked)
@ -188,18 +186,6 @@ class BibleImportForm(OpenLPWizard):
self.csvLayout = QtGui.QFormLayout(self.csvWidget) self.csvLayout = QtGui.QFormLayout(self.csvWidget)
self.csvLayout.setMargin(0) self.csvLayout.setMargin(0)
self.csvLayout.setObjectName(u'CsvLayout') self.csvLayout.setObjectName(u'CsvLayout')
self.csvTestamentsLabel = QtGui.QLabel(self.csvWidget)
self.csvTestamentsLabel.setObjectName(u'CsvTestamentsLabel')
self.csvTestamentsLayout = QtGui.QHBoxLayout()
self.csvTestamentsLayout.setObjectName(u'CsvTestamentsLayout')
self.csvTestamentsEdit = QtGui.QLineEdit(self.csvWidget)
self.csvTestamentsEdit.setObjectName(u'CsvTestamentsEdit')
self.csvTestamentsLayout.addWidget(self.csvTestamentsEdit)
self.csvTestamentsButton = QtGui.QToolButton(self.csvWidget)
self.csvTestamentsButton.setIcon(self.openIcon)
self.csvTestamentsButton.setObjectName(u'CsvTestamentsButton')
self.csvTestamentsLayout.addWidget(self.csvTestamentsButton)
self.csvLayout.addRow(self.csvTestamentsLabel, self.csvTestamentsLayout)
self.csvBooksLabel = QtGui.QLabel(self.csvWidget) self.csvBooksLabel = QtGui.QLabel(self.csvWidget)
self.csvBooksLabel.setObjectName(u'CsvBooksLabel') self.csvBooksLabel.setObjectName(u'CsvBooksLabel')
self.csvBooksLayout = QtGui.QHBoxLayout() self.csvBooksLayout = QtGui.QHBoxLayout()
@ -384,8 +370,6 @@ class BibleImportForm(OpenLPWizard):
translate('BiblesPlugin.ImportWizardForm', 'Bible file:')) translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
self.osisFileLabel.setText( self.osisFileLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Bible file:')) translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
self.csvTestamentsLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Testaments file:'))
self.csvBooksLabel.setText( self.csvBooksLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Books file:')) translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
self.csvVersesLabel.setText( self.csvVersesLabel.setText(
@ -436,7 +420,6 @@ class BibleImportForm(OpenLPWizard):
# Align all QFormLayouts towards each other. # Align all QFormLayouts towards each other.
labelWidth = max(self.formatLabel.minimumSizeHint().width(), labelWidth = max(self.formatLabel.minimumSizeHint().width(),
self.osisFileLabel.minimumSizeHint().width(), self.osisFileLabel.minimumSizeHint().width(),
self.csvTestamentsLabel.minimumSizeHint().width(),
self.csvBooksLabel.minimumSizeHint().width(), self.csvBooksLabel.minimumSizeHint().width(),
self.csvVersesLabel.minimumSizeHint().width(), self.csvVersesLabel.minimumSizeHint().width(),
self.openSongFileLabel.minimumSizeHint().width(), self.openSongFileLabel.minimumSizeHint().width(),
@ -458,14 +441,6 @@ class BibleImportForm(OpenLPWizard):
self.osisFileEdit.setFocus() self.osisFileEdit.setFocus()
return False return False
elif self.field(u'source_format').toInt()[0] == BibleFormat.CSV: elif self.field(u'source_format').toInt()[0] == BibleFormat.CSV:
if not self.field(u'csv_testamentsfile').toString():
answer = critical_error_message_box(UiStrings().NFSs,
translate('BiblesPlugin.ImportWizardForm',
'You have not specified a testaments file. Do you '
'want to proceed with the import?'), question=True)
if answer == QtGui.QMessageBox.No:
self.csvTestamentsEdit.setFocus()
return False
if not self.field(u'csv_booksfile').toString(): if not self.field(u'csv_booksfile').toString():
critical_error_message_box(UiStrings().NFSs, critical_error_message_box(UiStrings().NFSs,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
@ -498,6 +473,7 @@ class BibleImportForm(OpenLPWizard):
license_version = unicode(self.field(u'license_version').toString()) license_version = unicode(self.field(u'license_version').toString())
license_copyright = \ license_copyright = \
unicode(self.field(u'license_copyright').toString()) unicode(self.field(u'license_copyright').toString())
path = AppLocation.get_section_data_path(u'bibles')
if not license_version: if not license_version:
critical_error_message_box(UiStrings().EmptyField, critical_error_message_box(UiStrings().EmptyField,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
@ -519,6 +495,15 @@ class BibleImportForm(OpenLPWizard):
'a different Bible or first delete the existing one.')) 'a different Bible or first delete the existing one.'))
self.versionNameEdit.setFocus() self.versionNameEdit.setFocus()
return False return False
elif os.path.exists(os.path.join(path, clean_filename(
license_version))):
critical_error_message_box(
translate('BiblesPlugin.ImportWizardForm', 'Bible Exists'),
translate('BiblesPlugin.ImportWizardForm',
'This Bible already exists. Please import '
'a different Bible or first delete the existing one.'))
self.versionNameEdit.setFocus()
return False
return True return True
if self.currentPage() == self.progressPage: if self.currentPage() == self.progressPage:
return True return True
@ -543,14 +528,6 @@ class BibleImportForm(OpenLPWizard):
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OSIS, self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OSIS,
self.osisFileEdit) self.osisFileEdit)
def onCsvTestamentsBrowseButtonClicked(self):
"""
Show the file open dialog for the testaments CSV file.
"""
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.CSV,
self.csvTestamentsEdit, u'%s (*.csv)'
% translate('BiblesPlugin.ImportWizardForm', 'CSV File'))
def onCsvBooksBrowseButtonClicked(self): def onCsvBooksBrowseButtonClicked(self):
""" """
Show the file open dialog for the books CSV file. Show the file open dialog for the books CSV file.
@ -589,8 +566,6 @@ class BibleImportForm(OpenLPWizard):
""" """
self.selectPage.registerField(u'source_format', self.formatComboBox) self.selectPage.registerField(u'source_format', self.formatComboBox)
self.selectPage.registerField(u'osis_location', self.osisFileEdit) self.selectPage.registerField(u'osis_location', self.osisFileEdit)
self.selectPage.registerField(
u'csv_testamentsfile', self.csvTestamentsEdit)
self.selectPage.registerField(u'csv_booksfile', self.csvBooksEdit) self.selectPage.registerField(u'csv_booksfile', self.csvBooksEdit)
self.selectPage.registerField(u'csv_versefile', self.csvVersesEdit) self.selectPage.registerField(u'csv_versefile', self.csvVersesEdit)
self.selectPage.registerField(u'opensong_file', self.openSongFileEdit) self.selectPage.registerField(u'opensong_file', self.openSongFileEdit)
@ -619,7 +594,6 @@ class BibleImportForm(OpenLPWizard):
self.cancelButton.setVisible(True) self.cancelButton.setVisible(True)
self.setField(u'source_format', QtCore.QVariant(0)) self.setField(u'source_format', QtCore.QVariant(0))
self.setField(u'osis_location', QtCore.QVariant('')) self.setField(u'osis_location', QtCore.QVariant(''))
self.setField(u'csv_testamentsfile', QtCore.QVariant(''))
self.setField(u'csv_booksfile', QtCore.QVariant('')) self.setField(u'csv_booksfile', QtCore.QVariant(''))
self.setField(u'csv_versefile', QtCore.QVariant('')) self.setField(u'csv_versefile', QtCore.QVariant(''))
self.setField(u'opensong_file', QtCore.QVariant('')) self.setField(u'opensong_file', QtCore.QVariant(''))
@ -646,46 +620,27 @@ class BibleImportForm(OpenLPWizard):
""" """
Load the lists of Crosswalk, BibleGateway and Bibleserver bibles. Load the lists of Crosswalk, BibleGateway and Bibleserver bibles.
""" """
filepath = AppLocation.get_directory(AppLocation.PluginsDir)
filepath = os.path.join(filepath, u'bibles', u'resources')
# Load Crosswalk Bibles. # Load Crosswalk Bibles.
self.loadBibleResourceFile( self.loadBibleResource(WebDownload.Crosswalk)
os.path.join(filepath, u'crosswalkbooks.csv'),
WebDownload.Crosswalk)
# Load BibleGateway Bibles. # Load BibleGateway Bibles.
self.loadBibleResourceFile(os.path.join(filepath, u'biblegateway.csv'), self.loadBibleResource(WebDownload.BibleGateway)
WebDownload.BibleGateway)
# Load and Bibleserver Bibles. # Load and Bibleserver Bibles.
self.loadBibleResourceFile(os.path.join(filepath, u'bibleserver.csv'), self.loadBibleResource(WebDownload.Bibleserver)
WebDownload.Bibleserver)
def loadBibleResourceFile(self, file_path_name, download_type): def loadBibleResource(self, download_type):
""" """
Loads a web bible resource file. Loads a web bible from bible_resources.sqlite.
``file_path_name``
The file to load including the file's path.
``download_type`` ``download_type``
The WebDownload type this file is for. The WebDownload type e.g. bibleserver.
""" """
self.web_bible_list[download_type] = {} self.web_bible_list[download_type] = {}
books_file = None bibles = BiblesResourcesDB.get_webbibles(
try:
books_file = open(file_path_name, 'rb')
dialect = csv.Sniffer().sniff(books_file.read(1024))
books_file.seek(0)
books_reader = csv.reader(books_file, dialect)
for line in books_reader:
ver = string_is_unicode(line[0])
name = string_is_unicode(line[1])
self.web_bible_list[download_type][ver] = name.strip()
except IOError:
log.exception(u'%s resources missing' %
WebDownload.Names[download_type]) WebDownload.Names[download_type])
finally: for bible in bibles:
if books_file: version = bible[u'name']
books_file.close() name = bible[u'abbreviation']
self.web_bible_list[download_type][version] = name.strip()
def preWizard(self): def preWizard(self):
""" """
@ -720,8 +675,7 @@ class BibleImportForm(OpenLPWizard):
elif bible_type == BibleFormat.CSV: elif bible_type == BibleFormat.CSV:
# Import a CSV bible. # Import a CSV bible.
importer = self.manager.import_bible(BibleFormat.CSV, importer = self.manager.import_bible(BibleFormat.CSV,
name=license_version, testamentsfile=unicode( name=license_version,
self.field(u'csv_testamentsfile').toString()),
booksfile=unicode(self.field(u'csv_booksfile').toString()), booksfile=unicode(self.field(u'csv_booksfile').toString()),
versefile=unicode(self.field(u'csv_versefile').toString()) versefile=unicode(self.field(u'csv_versefile').toString())
) )
@ -752,7 +706,7 @@ class BibleImportForm(OpenLPWizard):
name=license_version, name=license_version,
filename=unicode(self.field(u'openlp1_location').toString()) filename=unicode(self.field(u'openlp1_location').toString())
) )
if importer.do_import(): if importer.do_import(license_version):
self.manager.save_meta_data(license_version, license_version, self.manager.save_meta_data(license_version, license_version,
license_copyright, license_permissions) license_copyright, license_permissions)
self.manager.reload_bibles() self.manager.reload_bibles()

View File

@ -0,0 +1,785 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, #
# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
The bible import functions for OpenLP
"""
import logging
import os.path
import re
import shutil
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsManager, translate, \
check_directory_exists
from openlp.core.lib.db import delete_database
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import AppLocation, delete_file
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB,\
BiblesResourcesDB, clean_filename
from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract
log = logging.getLogger(__name__)
class BibleUpgradeForm(OpenLPWizard):
"""
This is the Bible Upgrade Wizard, which allows easy importing of Bibles
into OpenLP from older OpenLP2 database versions.
"""
log.info(u'BibleUpgradeForm loaded')
def __init__(self, parent, manager, bibleplugin):
"""
Instantiate the wizard, and run any extra setup we need to.
``parent``
The QWidget-derived parent of the wizard.
``manager``
The Bible manager.
``bibleplugin``
The Bible plugin.
"""
self.manager = manager
self.mediaItem = bibleplugin.mediaItem
self.suffix = u'.sqlite'
self.settingsSection = u'bibles'
self.path = AppLocation.get_section_data_path(
self.settingsSection)
self.files = self.manager.old_bible_databases
self.success = {}
self.newbibles = {}
OpenLPWizard.__init__(self, parent, bibleplugin, u'bibleUpgradeWizard',
u':/wizards/wizard_importbible.bmp')
def setupUi(self, image):
"""
Set up the UI for the bible wizard.
"""
OpenLPWizard.setupUi(self, image)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import)
def stop_import(self):
"""
Stops the import of the Bible.
"""
log.debug(u'Stopping import')
self.stop_import_flag = True
def onCheckBoxIndexChanged(self, index):
"""
Show/Hide warnings if CheckBox state has changed
"""
for number, filename in enumerate(self.files):
if not self.checkBox[number].checkState() == QtCore.Qt.Checked:
self.verticalWidget[number].hide()
self.formWidget[number].hide()
else:
version_name = unicode(self.versionNameEdit[number].text())
if self.manager.exists(version_name):
self.verticalWidget[number].show()
self.formWidget[number].show()
def reject(self):
"""
Stop the wizard on cancel button, close button or ESC key.
"""
log.debug(u'Wizard cancelled by user')
self.stop_import_flag = True
if not self.currentPage() == self.progressPage:
self.done(QtGui.QDialog.Rejected)
else:
self.postWizard()
def onCurrentIdChanged(self, pageId):
"""
Perform necessary functions depending on which wizard page is active.
"""
if self.page(pageId) == self.progressPage:
self.preWizard()
self.performWizard()
self.postWizard()
elif self.page(pageId) == self.selectPage and self.maxBibles == 0:
self.next()
def onBackupBrowseButtonClicked(self):
"""
Show the file open dialog for the OSIS file.
"""
filename = QtGui.QFileDialog.getExistingDirectory(self, translate(
'BiblesPlugin.UpgradeWizardForm', 'Select a Backup Directory'),
os.path.dirname(SettingsManager.get_last_dir(
self.plugin.settingsSection, 1)))
if filename:
self.backupDirectoryEdit.setText(filename)
SettingsManager.set_last_dir(self.plugin.settingsSection,
filename, 1)
def onNoBackupCheckBoxToggled(self, checked):
"""
Enable or disable the backup directory widgets.
"""
self.backupDirectoryEdit.setEnabled(not checked)
self.backupBrowseButton.setEnabled(not checked)
def backupOldBibles(self, backup_directory):
"""
Backup old bible databases in a given folder.
"""
check_directory_exists(backup_directory)
success = True
for filename in self.files:
try:
shutil.copy(os.path.join(self.path, filename[0]),
backup_directory)
except:
success = False
return success
def customInit(self):
"""
Perform any custom initialisation for bible upgrading.
"""
self.manager.set_process_dialog(self)
self.restart()
def customSignals(self):
"""
Set up the signals used in the bible importer.
"""
QtCore.QObject.connect(self.backupBrowseButton,
QtCore.SIGNAL(u'clicked()'), self.onBackupBrowseButtonClicked)
QtCore.QObject.connect(self.noBackupCheckBox,
QtCore.SIGNAL(u'toggled(bool)'), self.onNoBackupCheckBoxToggled)
def addCustomPages(self):
"""
Add the bible import specific wizard pages.
"""
# Backup Page
self.backupPage = QtGui.QWizardPage()
self.backupPage.setObjectName(u'BackupPage')
self.backupLayout = QtGui.QVBoxLayout(self.backupPage)
self.backupLayout.setObjectName(u'BackupLayout')
self.backupInfoLabel = QtGui.QLabel(self.backupPage)
self.backupInfoLabel.setOpenExternalLinks(True)
self.backupInfoLabel.setTextFormat(QtCore.Qt.RichText)
self.backupInfoLabel.setWordWrap(True)
self.backupInfoLabel.setObjectName(u'backupInfoLabel')
self.backupLayout.addWidget(self.backupInfoLabel)
self.selectLabel = QtGui.QLabel(self.backupPage)
self.selectLabel.setObjectName(u'selectLabel')
self.backupLayout.addWidget(self.selectLabel)
self.formLayout = QtGui.QFormLayout()
self.formLayout.setMargin(0)
self.formLayout.setObjectName(u'FormLayout')
self.backupDirectoryLabel = QtGui.QLabel(self.backupPage)
self.backupDirectoryLabel.setObjectName(u'backupDirectoryLabel')
self.backupDirectoryLayout = QtGui.QHBoxLayout()
self.backupDirectoryLayout.setObjectName(u'BackupDirectoryLayout')
self.backupDirectoryEdit = QtGui.QLineEdit(self.backupPage)
self.backupDirectoryEdit.setObjectName(u'BackupFolderEdit')
self.backupDirectoryLayout.addWidget(self.backupDirectoryEdit)
self.backupBrowseButton = QtGui.QToolButton(self.backupPage)
self.backupBrowseButton.setIcon(self.openIcon)
self.backupBrowseButton.setObjectName(u'BackupBrowseButton')
self.backupDirectoryLayout.addWidget(self.backupBrowseButton)
self.formLayout.addRow(self.backupDirectoryLabel,
self.backupDirectoryLayout)
self.backupLayout.addLayout(self.formLayout)
self.noBackupCheckBox = QtGui.QCheckBox(self.backupPage)
self.noBackupCheckBox.setObjectName('NoBackupCheckBox')
self.backupLayout.addWidget(self.noBackupCheckBox)
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.backupLayout.addItem(self.spacer)
self.addPage(self.backupPage)
# Select Page
self.selectPage = QtGui.QWizardPage()
self.selectPage.setObjectName(u'SelectPage')
self.pageLayout = QtGui.QVBoxLayout(self.selectPage)
self.pageLayout.setObjectName(u'pageLayout')
self.scrollArea = QtGui.QScrollArea(self.selectPage)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName(u'scrollArea')
self.scrollArea.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.scrollAreaContents = QtGui.QWidget(self.scrollArea)
self.scrollAreaContents.setObjectName(u'scrollAreaContents')
self.formLayout = QtGui.QVBoxLayout(self.scrollAreaContents)
self.formLayout.setSpacing(2)
self.formLayout.setObjectName(u'formLayout')
self.addScrollArea()
self.pageLayout.addWidget(self.scrollArea)
self.addPage(self.selectPage)
def addScrollArea(self):
"""
Add the content to the scrollArea.
"""
self.checkBox = {}
self.versionNameEdit = {}
self.versionNameLabel = {}
self.versionInfoLabel = {}
self.versionInfoPixmap = {}
self.verticalWidget = {}
self.horizontalLayout = {}
self.formWidget = {}
self.formLayoutAttention = {}
for number, filename in enumerate(self.files):
bible = OldBibleDB(self.mediaItem, path=self.path, file=filename[0])
self.checkBox[number] = QtGui.QCheckBox(self.scrollAreaContents)
checkBoxName = u'checkBox[%d]' % number
self.checkBox[number].setObjectName(checkBoxName)
self.checkBox[number].setText(bible.get_name())
self.checkBox[number].setCheckState(QtCore.Qt.Checked)
self.formLayout.addWidget(self.checkBox[number])
self.verticalWidget[number] = QtGui.QWidget(self.scrollAreaContents)
verticalWidgetName = u'verticalWidget[%d]' % number
self.verticalWidget[number].setObjectName(verticalWidgetName)
self.horizontalLayout[number] = QtGui.QHBoxLayout(
self.verticalWidget[number])
self.horizontalLayout[number].setContentsMargins(25, 0, 0, 0)
horizontalLayoutName = u'horizontalLayout[%d]' % number
self.horizontalLayout[number].setObjectName(horizontalLayoutName)
self.versionInfoPixmap[number] = QtGui.QLabel(
self.verticalWidget[number])
versionInfoPixmapName = u'versionInfoPixmap[%d]' % number
self.versionInfoPixmap[number].setObjectName(versionInfoPixmapName)
self.versionInfoPixmap[number].setPixmap(QtGui.QPixmap(
u':/bibles/bibles_upgrade_alert.png'))
self.versionInfoPixmap[number].setAlignment(QtCore.Qt.AlignRight)
self.horizontalLayout[number].addWidget(
self.versionInfoPixmap[number])
self.versionInfoLabel[number] = QtGui.QLabel(
self.verticalWidget[number])
versionInfoLabelName = u'versionInfoLabel[%d]' % number
self.versionInfoLabel[number].setObjectName(versionInfoLabelName)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.versionInfoLabel[number].sizePolicy().hasHeightForWidth())
self.versionInfoLabel[number].setSizePolicy(sizePolicy)
self.horizontalLayout[number].addWidget(
self.versionInfoLabel[number])
self.formLayout.addWidget(self.verticalWidget[number])
self.formWidget[number] = QtGui.QWidget(self.scrollAreaContents)
formWidgetName = u'formWidget[%d]' % number
self.formWidget[number].setObjectName(formWidgetName)
self.formLayoutAttention[number] = QtGui.QFormLayout(
self.formWidget[number])
self.formLayoutAttention[number].setContentsMargins(25, 0, 0, 5)
formLayoutAttentionName = u'formLayoutAttention[%d]' % number
self.formLayoutAttention[number].setObjectName(
formLayoutAttentionName)
self.versionNameLabel[number] = QtGui.QLabel(
self.formWidget[number])
self.versionNameLabel[number].setObjectName(u'VersionNameLabel')
self.formLayoutAttention[number].setWidget(0,
QtGui.QFormLayout.LabelRole, self.versionNameLabel[number])
self.versionNameEdit[number] = QtGui.QLineEdit(
self.formWidget[number])
self.versionNameEdit[number].setObjectName(u'VersionNameEdit')
self.formLayoutAttention[number].setWidget(0,
QtGui.QFormLayout.FieldRole, self.versionNameEdit[number])
self.versionNameEdit[number].setText(bible.get_name())
self.formLayout.addWidget(self.formWidget[number])
# Set up the Signal for the checkbox.
QtCore.QObject.connect(self.checkBox[number],
QtCore.SIGNAL(u'stateChanged(int)'),
self.onCheckBoxIndexChanged)
self.spacerItem = QtGui.QSpacerItem(20, 5, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.formLayout.addItem(self.spacerItem)
self.scrollArea.setWidget(self.scrollAreaContents)
def clearScrollArea(self):
"""
Remove the content from the scrollArea.
"""
for number, filename in enumerate(self.files):
self.formLayout.removeWidget(self.checkBox[number])
self.checkBox[number].setParent(None)
self.horizontalLayout[number].removeWidget(
self.versionInfoPixmap[number])
self.versionInfoPixmap[number].setParent(None)
self.horizontalLayout[number].removeWidget(
self.versionInfoLabel[number])
self.versionInfoLabel[number].setParent(None)
self.formLayout.removeWidget(self.verticalWidget[number])
self.verticalWidget[number].setParent(None)
self.formLayoutAttention[number].removeWidget(
self.versionNameLabel[number])
self.versionNameLabel[number].setParent(None)
self.formLayoutAttention[number].removeWidget(
self.versionNameEdit[number])
self.formLayoutAttention[number].deleteLater()
self.versionNameEdit[number].setParent(None)
self.formLayout.removeWidget(self.formWidget[number])
self.formWidget[number].setParent(None)
self.formLayout.removeItem(self.spacerItem)
def retranslateUi(self):
"""
Allow for localisation of the bible import wizard.
"""
self.setWindowTitle(translate('BiblesPlugin.UpgradeWizardForm',
'Bible Upgrade Wizard'))
self.titleLabel.setText(WizardStrings.HeaderStyle %
translate('OpenLP.Ui', 'Welcome to the Bible Upgrade Wizard'))
self.informationLabel.setText(
translate('BiblesPlugin.UpgradeWizardForm',
'This wizard will help you to upgrade your existing Bibles from a '
'prior version of OpenLP 2. Click the next button below to start '
'the upgrade process.'))
self.backupPage.setTitle(
translate('BiblesPlugin.UpgradeWizardForm',
'Select Backup Directory'))
self.backupPage.setSubTitle(
translate('BiblesPlugin.UpgradeWizardForm',
'Please select a backup directory for your Bibles'))
self.backupInfoLabel.setText(translate('BiblesPlugin.UpgradeWizardForm',
'Previous releases of OpenLP 2.0 are unable to use upgraded Bibles.'
' This will create a backup of your current Bibles so that you can '
'simply copy the files back to your OpenLP data directory if you '
'need to revert to a previous release of OpenLP. Instructions on '
'how to restore the files can be found in our <a href="'
'http://wiki.openlp.org/faq">Frequently Asked Questions</a>.'))
self.selectLabel.setText(translate('BiblesPlugin.UpgradeWizardForm',
'Please select a backup location for your Bibles.'))
self.backupDirectoryLabel.setText(
translate('BiblesPlugin.UpgradeWizardForm', 'Backup Directory:'))
self.noBackupCheckBox.setText(
translate('BiblesPlugin.UpgradeWizardForm',
'There is no need to backup my Bibles'))
self.selectPage.setTitle(
translate('BiblesPlugin.UpgradeWizardForm',
'Select Bibles'))
self.selectPage.setSubTitle(
translate('BiblesPlugin.UpgradeWizardForm',
'Please select the Bibles to upgrade'))
for number, bible in enumerate(self.files):
self.versionNameLabel[number].setText(
translate('BiblesPlugin.UpgradeWizardForm', 'Version name:'))
self.versionInfoLabel[number].setText(
translate('BiblesPlugin.UpgradeWizardForm', 'This '
'Bible still exists. Please change the name or uncheck it.'))
self.progressPage.setTitle(translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading'))
self.progressPage.setSubTitle(
translate('BiblesPlugin.UpgradeWizardForm',
'Please wait while your Bibles are upgraded.'))
self.progressLabel.setText(WizardStrings.Ready)
self.progressBar.setFormat(u'%p%')
def validateCurrentPage(self):
"""
Validate the current page before moving on to the next page.
"""
if self.currentPage() == self.welcomePage:
return True
elif self.currentPage() == self.backupPage:
if not self.noBackupCheckBox.checkState() == QtCore.Qt.Checked:
backup_path = unicode(self.backupDirectoryEdit.text())
if not backup_path:
critical_error_message_box(UiStrings().EmptyField,
translate('BiblesPlugin.UpgradeWizardForm',
'You need to specify a Backup Directory for your '
'Bibles.'))
self.backupDirectoryEdit.setFocus()
return False
else:
if not self.backupOldBibles(backup_path):
critical_error_message_box(UiStrings().Error,
translate('BiblesPlugin.UpgradeWizardForm',
'The backup was not successful.\nTo backup your '
'Bibles you need permission to write to the given '
'directory. If you have write permissions and this '
'error still occurs, please report a bug.'))
return False
return True
elif self.currentPage() == self.selectPage:
for number, filename in enumerate(self.files):
if not self.checkBox[number].checkState() == QtCore.Qt.Checked:
continue
version_name = unicode(self.versionNameEdit[number].text())
if not version_name:
critical_error_message_box(UiStrings().EmptyField,
translate('BiblesPlugin.UpgradeWizardForm',
'You need to specify a version name for your Bible.'))
self.versionNameEdit[number].setFocus()
return False
elif self.manager.exists(version_name):
critical_error_message_box(
translate('BiblesPlugin.UpgradeWizardForm',
'Bible Exists'),
translate('BiblesPlugin.UpgradeWizardForm',
'This Bible already exists. Please upgrade '
'a different Bible, delete the existing one or '
'uncheck.'))
self.versionNameEdit[number].setFocus()
return False
elif os.path.exists(os.path.join(self.path, clean_filename(
version_name))) and version_name == filename[1]:
newfilename = u'old_database_%s' % filename[0]
if not os.path.exists(os.path.join(self.path,
newfilename)):
os.rename(os.path.join(self.path, filename[0]),
os.path.join(self.path, newfilename))
self.files[number] = [newfilename, filename[1]]
continue
else:
critical_error_message_box(
translate('BiblesPlugin.UpgradeWizardForm',
'Bible Exists'),
translate('BiblesPlugin.UpgradeWizardForm',
'This Bible already exists. Please upgrade '
'a different Bible, delete the existing one or '
'uncheck.'))
self.verticalWidget[number].show()
self.formWidget[number].show()
self.versionNameEdit[number].setFocus()
return False
elif os.path.exists(os.path.join(self.path,
clean_filename(version_name))):
critical_error_message_box(
translate('BiblesPlugin.UpgradeWizardForm',
'Bible Exists'),
translate('BiblesPlugin.UpgradeWizardForm',
'This Bible already exists. Please upgrade '
'a different Bible, delete the existing one or '
'uncheck.'))
self.versionNameEdit[number].setFocus()
return False
return True
if self.currentPage() == self.progressPage:
return True
def setDefaults(self):
"""
Set default values for the wizard pages.
"""
log.debug(u'BibleUpgrade setDefaults')
settings = QtCore.QSettings()
settings.beginGroup(self.plugin.settingsSection)
self.stop_import_flag = False
self.success.clear()
self.newbibles.clear()
self.clearScrollArea()
self.files = self.manager.old_bible_databases
self.addScrollArea()
self.retranslateUi()
self.maxBibles = len(self.files)
for number, filename in enumerate(self.files):
self.checkBox[number].setCheckState(QtCore.Qt.Checked)
oldname = filename[1]
if self.manager.exists(oldname):
self.verticalWidget[number].show()
self.formWidget[number].show()
else:
self.verticalWidget[number].hide()
self.formWidget[number].hide()
self.progressBar.show()
self.restart()
self.finishButton.setVisible(False)
self.cancelButton.setVisible(True)
settings.endGroup()
def preWizard(self):
"""
Prepare the UI for the upgrade.
"""
OpenLPWizard.preWizard(self)
self.progressLabel.setText(translate(
'BiblesPlugin.UpgradeWizardForm',
'Starting upgrading Bible(s)...'))
Receiver.send_message(u'openlp_process_events')
def performWizard(self):
"""
Perform the actual upgrade.
"""
self.include_webbible = False
proxy_server = None
if self.maxBibles == 0:
self.progressLabel.setText(
translate('BiblesPlugin.UpgradeWizardForm', 'There are no '
'Bibles available to upgrade.'))
self.progressBar.hide()
return
self.maxBibles = 0
for number, file in enumerate(self.files):
if self.checkBox[number].checkState() == QtCore.Qt.Checked:
self.maxBibles += 1
number = 0
for biblenumber, filename in enumerate(self.files):
if self.stop_import_flag:
bible_failed = True
break
bible_failed = False
self.success[biblenumber] = False
if not self.checkBox[biblenumber].checkState() == QtCore.Qt.Checked:
continue
self.progressBar.reset()
oldbible = OldBibleDB(self.mediaItem, path=self.path,
file=filename[0])
name = filename[1]
if name is None:
delete_file(os.path.join(self.path, filename[0]))
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed')) %
(number + 1, self.maxBibles, name),
self.progressBar.maximum() - self.progressBar.value())
number += 1
continue
self.progressLabel.setText(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nUpgrading ...')) %
(number + 1, self.maxBibles, name))
if os.path.exists(os.path.join(self.path, filename[0])):
name = unicode(self.versionNameEdit[biblenumber].text())
self.newbibles[number] = BibleDB(self.mediaItem, path=self.path,
name=name)
self.newbibles[number].register(self.plugin.upgrade_wizard)
metadata = oldbible.get_metadata()
webbible = False
meta_data = {}
for meta in metadata:
meta_data[meta[u'key']] = meta[u'value']
if not meta[u'key'] == u'Version' and not meta[u'key'] == \
u'dbversion':
self.newbibles[number].create_meta(meta[u'key'],
meta[u'value'])
if meta[u'key'] == u'download source':
webbible = True
self.include_webbible = True
if meta.has_key(u'proxy server'):
proxy_server = meta[u'proxy server']
if webbible:
if meta_data[u'download source'].lower() == u'crosswalk':
handler = CWExtract(proxy_server)
elif meta_data[u'download source'].lower() == u'biblegateway':
handler = BGExtract(proxy_server)
elif meta_data[u'download source'].lower() == u'bibleserver':
handler = BSExtract(proxy_server)
books = handler.get_books_from_http(meta_data[u'download name'])
if not books:
log.error(u'Upgrading books from %s - download '\
u'name: "%s" failed' % (
meta_data[u'download source'],
meta_data[u'download name']))
delete_database(self.path, clean_filename(name))
del self.newbibles[number]
critical_error_message_box(
translate('BiblesPlugin.UpgradeWizardForm',
'Download Error'),
translate('BiblesPlugin.UpgradeWizardForm',
'To upgrade your Web Bibles an Internet connection is '
'required. If you have a working Internet connection '
'and this error still occurs, please report a bug.'))
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed')) %
(number + 1, self.maxBibles, name),
self.progressBar.maximum() - self.progressBar.value())
number += 1
continue
bible = BiblesResourcesDB.get_webbible(
meta_data[u'download name'],
meta_data[u'download source'].lower())
if bible and bible[u'language_id']:
language_id = bible[u'language_id']
self.newbibles[number].create_meta(u'language_id',
language_id)
else:
language_id = self.newbibles[number].get_language(name)
if not language_id:
log.warn(u'Upgrading from "%s" failed' % filename[0])
delete_database(self.path, clean_filename(name))
del self.newbibles[number]
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed')) %
(number + 1, self.maxBibles, name),
self.progressBar.maximum() - self.progressBar.value())
number += 1
continue
self.progressBar.setMaximum(len(books))
for book in books:
if self.stop_import_flag:
bible_failed = True
break
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\n'
'Upgrading %s ...')) %
(number + 1, self.maxBibles, name, book))
book_ref_id = self.newbibles[number].\
get_book_ref_id_by_name(book, len(books), language_id)
if not book_ref_id:
log.warn(u'Upgrading books from %s - download '\
u'name: "%s" aborted by user' % (
meta_data[u'download source'],
meta_data[u'download name']))
delete_database(self.path, clean_filename(name))
del self.newbibles[number]
bible_failed = True
break
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.newbibles[number].create_book(book,
book_ref_id, book_details[u'testament_id'])
# Try to import still downloaded verses
oldbook = oldbible.get_book(book)
if oldbook:
verses = oldbible.get_verses(oldbook[u'id'])
if not verses:
log.warn(u'No verses found to import for book '
u'"%s"', book)
continue
for verse in verses:
if self.stop_import_flag:
bible_failed = True
break
self.newbibles[number].create_verse(db_book.id,
int(verse[u'chapter']),
int(verse[u'verse']), unicode(verse[u'text']))
Receiver.send_message(u'openlp_process_events')
self.newbibles[number].session.commit()
else:
language_id = self.newbibles[number].get_object(BibleMeta,
u'language_id')
if not language_id:
language_id = self.newbibles[number].get_language(name)
if not language_id:
log.warn(u'Upgrading books from "%s" failed' % name)
delete_database(self.path, clean_filename(name))
del self.newbibles[number]
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed')) %
(number + 1, self.maxBibles, name),
self.progressBar.maximum() - self.progressBar.value())
number += 1
continue
books = oldbible.get_books()
self.progressBar.setMaximum(len(books))
for book in books:
if self.stop_import_flag:
bible_failed = True
break
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\n'
'Upgrading %s ...')) %
(number + 1, self.maxBibles, name, book[u'name']))
book_ref_id = self.newbibles[number].\
get_book_ref_id_by_name(book[u'name'], len(books),
language_id)
if not book_ref_id:
log.warn(u'Upgrading books from %s " '\
'failed - aborted by user' % name)
delete_database(self.path, clean_filename(name))
del self.newbibles[number]
bible_failed = True
break
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.newbibles[number].create_book(book[u'name'],
book_ref_id, book_details[u'testament_id'])
verses = oldbible.get_verses(book[u'id'])
if not verses:
log.warn(u'No verses found to import for book '
u'"%s"', book[u'name'])
self.newbibles[number].delete_book(db_book)
continue
for verse in verses:
if self.stop_import_flag:
bible_failed = True
break
self.newbibles[number].create_verse(db_book.id,
int(verse[u'chapter']),
int(verse[u'verse']), unicode(verse[u'text']))
Receiver.send_message(u'openlp_process_events')
self.newbibles[number].session.commit()
if not bible_failed:
self.newbibles[number].create_meta(u'Version', name)
delete_file(os.path.join(self.path, filename[0]))
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\n'
'Done')) %
(number + 1, self.maxBibles, name))
self.success[biblenumber] = True
else:
self.incrementProgressBar(unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed')) %
(number + 1, self.maxBibles, name),
self.progressBar.maximum() - self.progressBar.value())
delete_database(self.path, clean_filename(name))
number += 1
def postWizard(self):
"""
Clean up the UI after the import has finished.
"""
successful_import = 0
failed_import = 0
for number, filename in enumerate(self.files):
if number in self.success and self.success[number] == True:
successful_import += 1
elif self.checkBox[number].checkState() == QtCore.Qt.Checked:
failed_import += 1
if failed_import > 0:
failed_import_text = unicode(translate(
'BiblesPlugin.UpgradeWizardForm',
', %s failed')) % failed_import
else:
failed_import_text = u''
if successful_import > 0:
if self.include_webbible:
self.progressLabel.setText(unicode(
translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading '
'Bible(s): %s successful%s\nPlease note, that verses from '
'Web Bibles will be downloaded\non demand and so an '
'Internet connection is required.')) %
(successful_import, failed_import_text))
else:
self.progressLabel.setText(unicode(
translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading '
'Bible(s): %s successful%s')) % (successful_import,
failed_import_text))
else:
self.progressLabel.setText(
translate('BiblesPlugin.UpgradeWizardForm', 'Upgrade '
'failed.'))
OpenLPWizard.postWizard(self)

View File

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, #
# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon #
# Tibble, Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
class Ui_BookNameDialog(object):
def setupUi(self, bookNameDialog):
bookNameDialog.setObjectName(u'bookNameDialog')
bookNameDialog.resize(400, 271)
self.bookNameLayout = QtGui.QVBoxLayout(bookNameDialog)
self.bookNameLayout.setSpacing(8)
self.bookNameLayout.setMargin(8)
self.bookNameLayout.setObjectName(u'bookNameLayout')
self.infoLabel = QtGui.QLabel(bookNameDialog)
self.infoLabel.setWordWrap(True)
self.infoLabel.setObjectName(u'infoLabel')
self.bookNameLayout.addWidget(self.infoLabel)
self.correspondingLayout = QtGui.QGridLayout()
self.correspondingLayout.setColumnStretch(1, 1)
self.correspondingLayout.setSpacing(8)
self.correspondingLayout.setObjectName(u'correspondingLayout')
self.currentLabel = QtGui.QLabel(bookNameDialog)
self.currentLabel.setObjectName(u'currentLabel')
self.correspondingLayout.addWidget(self.currentLabel, 0, 0, 1, 1)
self.currentBookLabel = QtGui.QLabel(bookNameDialog)
self.currentBookLabel.setObjectName(u'currentBookLabel')
self.correspondingLayout.addWidget(self.currentBookLabel, 0, 1, 1, 1)
self.correspondingLabel = QtGui.QLabel(bookNameDialog)
self.correspondingLabel.setObjectName(u'correspondingLabel')
self.correspondingLayout.addWidget(
self.correspondingLabel, 1, 0, 1, 1)
self.correspondingComboBox = QtGui.QComboBox(bookNameDialog)
self.correspondingComboBox.setObjectName(u'correspondingComboBox')
self.correspondingLayout.addWidget(
self.correspondingComboBox, 1, 1, 1, 1)
self.bookNameLayout.addLayout(self.correspondingLayout)
self.optionsGroupBox = QtGui.QGroupBox(bookNameDialog)
self.optionsGroupBox.setObjectName(u'optionsGroupBox')
self.optionsLayout = QtGui.QVBoxLayout(self.optionsGroupBox)
self.optionsLayout.setSpacing(8)
self.optionsLayout.setMargin(8)
self.optionsLayout.setObjectName(u'optionsLayout')
self.oldTestamentCheckBox = QtGui.QCheckBox(self.optionsGroupBox)
self.oldTestamentCheckBox.setObjectName(u'oldTestamentCheckBox')
self.oldTestamentCheckBox.setCheckState(QtCore.Qt.Checked)
self.optionsLayout.addWidget(self.oldTestamentCheckBox)
self.newTestamentCheckBox = QtGui.QCheckBox(self.optionsGroupBox)
self.newTestamentCheckBox.setObjectName(u'newTestamentCheckBox')
self.newTestamentCheckBox.setCheckState(QtCore.Qt.Checked)
self.optionsLayout.addWidget(self.newTestamentCheckBox)
self.apocryphaCheckBox = QtGui.QCheckBox(self.optionsGroupBox)
self.apocryphaCheckBox.setObjectName(u'apocryphaCheckBox')
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Checked)
self.optionsLayout.addWidget(self.apocryphaCheckBox)
self.bookNameLayout.addWidget(self.optionsGroupBox)
self.buttonBox = QtGui.QDialogButtonBox(bookNameDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.bookNameLayout.addWidget(self.buttonBox)
self.retranslateUi(bookNameDialog)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL(u'accepted()'),
bookNameDialog.accept)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL(u'rejected()'),
bookNameDialog.reject)
QtCore.QMetaObject.connectSlotsByName(bookNameDialog)
def retranslateUi(self, bookNameDialog):
bookNameDialog.setWindowTitle(translate('BiblesPlugin.BookNameDialog',
'Select Book Name'))
self.infoLabel.setText(translate('BiblesPlugin.BookNameDialog',
'The following book name cannot be matched up internally. Please '
'select the corresponding English name from the list.'))
self.currentLabel.setText(translate('BiblesPlugin.BookNameDialog',
'Current name:'))
self.correspondingLabel.setText(translate(
'BiblesPlugin.BookNameDialog', 'Corresponding name:'))
self.optionsGroupBox.setTitle(translate('BiblesPlugin.BookNameDialog',
'Show Books From'))
self.oldTestamentCheckBox.setText(translate(
'BiblesPlugin.BookNameDialog', 'Old Testament'))
self.newTestamentCheckBox.setText(translate(
'BiblesPlugin.BookNameDialog', 'New Testament'))
self.apocryphaCheckBox.setText(translate('BiblesPlugin.BookNameDialog',
'Apocrypha'))

View File

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, #
# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon #
# Tibble, Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Module implementing BookNameForm.
"""
import logging
from PyQt4.QtGui import QDialog
from PyQt4 import QtCore
from openlp.core.lib import translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.bibles.forms.booknamedialog import \
Ui_BookNameDialog
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
log = logging.getLogger(__name__)
class BookNameForm(QDialog, Ui_BookNameDialog):
"""
Class to manage a dialog which help the user to refer a book name a
to a english book name
"""
log.info(u'BookNameForm loaded')
def __init__(self, parent = None):
"""
Constructor
"""
QDialog.__init__(self, parent)
self.setupUi(self)
self.customSignals()
def customSignals(self):
"""
Set up the signals used in the booknameform.
"""
QtCore.QObject.connect(self.oldTestamentCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onCheckBoxIndexChanged)
QtCore.QObject.connect(self.newTestamentCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onCheckBoxIndexChanged)
QtCore.QObject.connect(self.apocryphaCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onCheckBoxIndexChanged)
def onCheckBoxIndexChanged(self, index):
"""
Reload Combobox if CheckBox state has changed
"""
self.reloadComboBox()
def reloadComboBox(self):
"""
Reload the Combobox items
"""
self.correspondingComboBox.clear()
items = BiblesResourcesDB.get_books()
for item in items:
addBook = True
for book in self.books:
if book.book_reference_id == item[u'id']:
addBook = False
break
if self.oldTestamentCheckBox.checkState() == QtCore.Qt.Unchecked \
and item[u'testament_id'] == 1:
addBook = False
elif self.newTestamentCheckBox.checkState() == QtCore.Qt.Unchecked \
and item[u'testament_id'] == 2:
addBook = False
elif self.apocryphaCheckBox.checkState() == QtCore.Qt.Unchecked \
and item[u'testament_id'] == 3:
addBook = False
if addBook:
self.correspondingComboBox.addItem(item[u'name'])
def exec_(self, name, books, maxbooks):
self.books = books
log.debug(maxbooks)
if maxbooks <= 27:
self.oldTestamentCheckBox.setCheckState(QtCore.Qt.Unchecked)
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Unchecked)
elif maxbooks <= 66:
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Unchecked)
self.reloadComboBox()
self.currentBookLabel.setText(unicode(name))
self.correspondingComboBox.setFocus()
return QDialog.exec_(self)
def accept(self):
if self.correspondingComboBox.currentText() == u'':
critical_error_message_box(
message=translate('BiblesPlugin.BookNameForm',
'You need to select a book.'))
self.correspondingComboBox.setFocus()
return False
else:
return QDialog.accept(self)

View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, #
# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon #
# Tibble, Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
class Ui_LanguageDialog(object):
def setupUi(self, languageDialog):
languageDialog.setObjectName(u'languageDialog')
languageDialog.resize(400, 165)
self.languageLayout = QtGui.QVBoxLayout(languageDialog)
self.languageLayout.setSpacing(8)
self.languageLayout.setMargin(8)
self.languageLayout.setObjectName(u'languageLayout')
self.bibleLabel = QtGui.QLabel(languageDialog)
self.bibleLabel.setObjectName(u'bibleLabel')
self.languageLayout.addWidget(self.bibleLabel)
self.infoLabel = QtGui.QLabel(languageDialog)
self.infoLabel.setWordWrap(True)
self.infoLabel.setObjectName(u'infoLabel')
self.languageLayout.addWidget(self.infoLabel)
self.languageHBoxLayout = QtGui.QHBoxLayout()
self.languageHBoxLayout.setSpacing(8)
self.languageHBoxLayout.setObjectName(u'languageHBoxLayout')
self.languageLabel = QtGui.QLabel(languageDialog)
self.languageLabel.setObjectName(u'languageLabel')
self.languageHBoxLayout.addWidget(self.languageLabel)
self.languageComboBox = QtGui.QComboBox(languageDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.languageComboBox.sizePolicy().hasHeightForWidth())
self.languageComboBox.setSizePolicy(sizePolicy)
self.languageComboBox.setObjectName(u'languageComboBox')
self.languageHBoxLayout.addWidget(self.languageComboBox)
self.languageLayout.addLayout(self.languageHBoxLayout)
self.buttonBox = QtGui.QDialogButtonBox(languageDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|
QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.languageLayout.addWidget(self.buttonBox)
self.retranslateUi(languageDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
languageDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'),
languageDialog.reject)
def retranslateUi(self, languageDialog):
languageDialog.setWindowTitle(
translate('BiblesPlugin.LanguageDialog', 'Select Language'))
self.bibleLabel.setText(translate('BiblesPlugin.LanguageDialog', ''))
self.infoLabel.setText(translate('BiblesPlugin.LanguageDialog',
'OpenLP is unable to determine the language of this translation '
'of the Bible. Please select the language from the list below.'))
self.languageLabel.setText(translate('BiblesPlugin.LanguageDialog',
'Language:'))

View File

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, #
# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon #
# Tibble, Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Module implementing LanguageForm.
"""
import logging
from PyQt4.QtGui import QDialog
from openlp.core.lib import translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.bibles.forms.languagedialog import \
Ui_LanguageDialog
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
log = logging.getLogger(__name__)
class LanguageForm(QDialog, Ui_LanguageDialog):
"""
Class to manage a dialog which ask the user for a language.
"""
log.info(u'LanguageForm loaded')
def __init__(self, parent = None):
"""
Constructor
"""
QDialog.__init__(self, parent)
self.setupUi(self)
def exec_(self, bible_name):
self.languageComboBox.addItem(u'')
if bible_name:
self.bibleLabel.setText(unicode(bible_name))
items = BiblesResourcesDB.get_languages()
for item in items:
self.languageComboBox.addItem(item[u'name'])
return QDialog.exec_(self)
def accept(self):
if self.languageComboBox.currentText() == u'':
critical_error_message_box(
message=translate('BiblesPlugin.LanguageForm',
'You need to choose a language.'))
self.languageComboBox.setFocus()
return False
else:
return QDialog.accept(self)

View File

@ -71,7 +71,7 @@ import chardet
import csv import csv
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate
from openlp.plugins.bibles.lib.db import BibleDB, Testament from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -79,6 +79,8 @@ class CSVBible(BibleDB):
""" """
This class provides a specialisation for importing of CSV Bibles. This class provides a specialisation for importing of CSV Bibles.
""" """
log.info(u'CSVBible loaded')
def __init__(self, parent, **kwargs): def __init__(self, parent, **kwargs):
""" """
Loads a Bible from a set of CVS files. Loads a Bible from a set of CVS files.
@ -87,48 +89,10 @@ class CSVBible(BibleDB):
""" """
log.info(self.__class__.__name__) log.info(self.__class__.__name__)
BibleDB.__init__(self, parent, **kwargs) BibleDB.__init__(self, parent, **kwargs)
try:
self.testamentsfile = kwargs[u'testamentsfile']
except KeyError:
self.testamentsfile = None
self.booksfile = kwargs[u'booksfile'] self.booksfile = kwargs[u'booksfile']
self.versesfile = kwargs[u'versefile'] self.versesfile = kwargs[u'versefile']
def setup_testaments(self): def do_import(self, bible_name=None):
"""
Overrides parent method so we can handle importing a testament file.
"""
if self.testamentsfile:
self.wizard.progressBar.setMinimum(0)
self.wizard.progressBar.setMaximum(2)
self.wizard.progressBar.setValue(0)
testaments_file = None
try:
details = get_file_encoding(self.testamentsfile)
testaments_file = open(self.testamentsfile, 'rb')
testaments_reader = csv.reader(testaments_file, delimiter=',',
quotechar='"')
for line in testaments_reader:
if self.stop_import_flag:
break
self.wizard.incrementProgressBar(unicode(
translate('BibleDB.Wizard',
'Importing testaments... %s')) %
unicode(line[1], details['encoding']), 0)
self.save_object(Testament.populate(
name=unicode(line[1], details['encoding'])))
Receiver.send_message(u'openlp_process_events')
except (IOError, IndexError):
log.exception(u'Loading testaments from file failed')
finally:
if testaments_file:
testaments_file.close()
self.wizard.incrementProgressBar(unicode(translate(
'BibleDB.Wizard', 'Importing testaments... done.')), 2)
else:
BibleDB.setup_testaments(self)
def do_import(self):
""" """
Import the bible books and verses. Import the bible books and verses.
""" """
@ -136,6 +100,10 @@ class CSVBible(BibleDB):
self.wizard.progressBar.setMinimum(0) self.wizard.progressBar.setMinimum(0)
self.wizard.progressBar.setMaximum(66) self.wizard.progressBar.setMaximum(66)
success = True success = True
language_id = self.get_language(bible_name)
if not language_id:
log.exception(u'Importing books from "%s" failed' % self.filename)
return False
books_file = None books_file = None
book_list = {} book_list = {}
# Populate the Tables # Populate the Tables
@ -149,8 +117,15 @@ class CSVBible(BibleDB):
self.wizard.incrementProgressBar(unicode( self.wizard.incrementProgressBar(unicode(
translate('BibleDB.Wizard', 'Importing books... %s')) % translate('BibleDB.Wizard', 'Importing books... %s')) %
unicode(line[2], details['encoding'])) unicode(line[2], details['encoding']))
book_ref_id = self.get_book_ref_id_by_name(
unicode(line[2], details['encoding']), 67, language_id)
if not book_ref_id:
log.exception(u'Importing books from "%s" '\
'failed' % self.booksfile)
return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
self.create_book(unicode(line[2], details['encoding']), self.create_book(unicode(line[2], details['encoding']),
unicode(line[3], details['encoding']), int(line[1])) book_ref_id, book_details[u'testament_id'])
book_list[int(line[0])] = unicode(line[2], details['encoding']) book_list[int(line[0])] = unicode(line[2], details['encoding'])
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
except (IOError, IndexError): except (IOError, IndexError):

View File

@ -27,16 +27,19 @@
import logging import logging
import chardet import chardet
import os
import re import re
import sqlite3
from PyQt4 import QtCore from PyQt4 import QtCore
from sqlalchemy import Column, ForeignKey, or_, Table, types from sqlalchemy import Column, ForeignKey, or_, Table, types
from sqlalchemy.orm import class_mapper, mapper, relation from sqlalchemy.orm import class_mapper, mapper, relation
from sqlalchemy.orm.exc import UnmappedClassError from sqlalchemy.orm.exc import UnmappedClassError
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate, check_directory_exists
from openlp.core.lib.db import BaseModel, init_db, Manager from openlp.core.lib.db import BaseModel, init_db, Manager
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import AppLocation
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -47,13 +50,6 @@ class BibleMeta(BaseModel):
pass pass
class Testament(BaseModel):
"""
Bible Testaments
"""
pass
class Book(BaseModel): class Book(BaseModel):
""" """
Song model Song model
@ -67,6 +63,18 @@ class Verse(BaseModel):
""" """
pass pass
def clean_filename(filename):
"""
Clean up the version name of the Bible and convert it into a valid
file name.
``filename``
The "dirty" file name or version name.
"""
if not isinstance(filename, unicode):
filename = unicode(filename, u'utf-8')
filename = re.sub(r'[^\w]+', u'_', filename).strip(u'_')
return filename + u'.sqlite'
def init_schema(url): def init_schema(url):
""" """
@ -81,19 +89,17 @@ def init_schema(url):
Column(u'key', types.Unicode(255), primary_key=True, index=True), Column(u'key', types.Unicode(255), primary_key=True, index=True),
Column(u'value', types.Unicode(255)), Column(u'value', types.Unicode(255)),
) )
testament_table = Table(u'testament', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(50)),
)
book_table = Table(u'book', metadata, book_table = Table(u'book', metadata,
Column(u'id', types.Integer, primary_key=True), Column(u'id', types.Integer, primary_key=True),
Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')), Column(u'book_reference_id', types.Integer, index=True),
Column(u'testament_reference_id', types.Integer),
Column(u'name', types.Unicode(50), index=True), Column(u'name', types.Unicode(50), index=True),
Column(u'abbreviation', types.Unicode(5), index=True),
) )
verse_table = Table(u'verse', metadata, verse_table = Table(u'verse', metadata,
Column(u'id', types.Integer, primary_key=True, index=True), Column(u'id', types.Integer, primary_key=True, index=True),
Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True), Column(u'book_id', types.Integer, ForeignKey(
u'book.id'), index=True),
Column(u'chapter', types.Integer, index=True), Column(u'chapter', types.Integer, index=True),
Column(u'verse', types.Integer, index=True), Column(u'verse', types.Integer, index=True),
Column(u'text', types.UnicodeText, index=True), Column(u'text', types.UnicodeText, index=True),
@ -103,11 +109,6 @@ def init_schema(url):
class_mapper(BibleMeta) class_mapper(BibleMeta)
except UnmappedClassError: except UnmappedClassError:
mapper(BibleMeta, meta_table) mapper(BibleMeta, meta_table)
try:
class_mapper(Testament)
except UnmappedClassError:
mapper(Testament, testament_table,
properties={'books': relation(Book, backref='testament')})
try: try:
class_mapper(Book) class_mapper(Book)
except UnmappedClassError: except UnmappedClassError:
@ -129,6 +130,7 @@ class BibleDB(QtCore.QObject, Manager):
methods, but benefit from the database methods in here via inheritance, methods, but benefit from the database methods in here via inheritance,
rather than depending on yet another object. rather than depending on yet another object.
""" """
log.info(u'BibleDB loaded')
def __init__(self, parent, **kwargs): def __init__(self, parent, **kwargs):
""" """
@ -156,12 +158,14 @@ class BibleDB(QtCore.QObject, Manager):
self.name = kwargs[u'name'] self.name = kwargs[u'name']
if not isinstance(self.name, unicode): if not isinstance(self.name, unicode):
self.name = unicode(self.name, u'utf-8') self.name = unicode(self.name, u'utf-8')
self.file = self.clean_filename(self.name) self.file = clean_filename(self.name)
if u'file' in kwargs: if u'file' in kwargs:
self.file = kwargs[u'file'] self.file = kwargs[u'file']
Manager.__init__(self, u'bibles', init_schema, self.file) Manager.__init__(self, u'bibles', init_schema, self.file)
if u'file' in kwargs: if u'file' in kwargs:
self.get_name() self.get_name()
if u'path' in kwargs:
self.path = kwargs[u'path']
self.wizard = None self.wizard = None
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import) QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import)
@ -181,19 +185,6 @@ class BibleDB(QtCore.QObject, Manager):
self.name = version_name.value if version_name else None self.name = version_name.value if version_name else None
return self.name return self.name
def clean_filename(self, old_filename):
"""
Clean up the version name of the Bible and convert it into a valid
file name.
``old_filename``
The "dirty" file name or version name.
"""
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 register(self, wizard): def register(self, wizard):
""" """
This method basically just initialialises the database. It is called This method basically just initialialises the database. It is called
@ -206,36 +197,40 @@ class BibleDB(QtCore.QObject, Manager):
""" """
self.wizard = wizard self.wizard = wizard
self.create_meta(u'dbversion', u'2') self.create_meta(u'dbversion', u'2')
self.setup_testaments()
return self.name return self.name
def setup_testaments(self): def create_book(self, name, bk_ref_id, testament=1):
"""
Initialise the testaments section of a bible with suitable defaults.
"""
self.save_object(Testament.populate(name=u'Old Testament'))
self.save_object(Testament.populate(name=u'New Testament'))
self.save_object(Testament.populate(name=u'Apocrypha'))
def create_book(self, name, abbrev, testament=1):
""" """
Add a book to the database. Add a book to the database.
``name`` ``name``
The name of the book. The name of the book.
``abbrev`` ``bk_ref_id``
The abbreviation of the book. The book_reference_id from bibles_resources.sqlite of the book.
``testament`` ``testament``
*Defaults to 1.* The id of the testament this book belongs to. *Defaults to 1.* The testament_reference_id from
bibles_resources.sqlite of the testament this book belongs to.
""" """
log.debug(u'create_book %s,%s', name, abbrev) log.debug(u'BibleDB.create_book("%s", "%s")', name, bk_ref_id)
book = Book.populate(name=name, abbreviation=abbrev, book = Book.populate(name=name, book_reference_id=bk_ref_id,
testament_id=testament) testament_reference_id=testament)
self.save_object(book) self.save_object(book)
return book return book
def delete_book(self, db_book):
"""
Delete a book from the database.
``db_book``
The book object.
"""
log.debug(u'BibleDB.delete_book("%s")', db_book.name)
if self.delete_object(Book, db_book.id):
return True
return False
def create_chapter(self, book_id, chapter, textlist): def create_chapter(self, book_id, chapter, textlist):
""" """
Add a chapter and its verses to a book. Add a chapter and its verses to a book.
@ -250,7 +245,7 @@ class BibleDB(QtCore.QObject, Manager):
A dict of the verses to be inserted. The key is the verse number, A dict of the verses to be inserted. The key is the verse number,
and the value is the verse text. and the value is the verse text.
""" """
log.debug(u'create_chapter %s,%s', book_id, chapter) log.debug(u'BibleDBcreate_chapter("%s", "%s")', book_id, chapter)
# Text list has book and chapter as first two elements of the array. # Text list has book and chapter as first two elements of the array.
for verse_number, verse_text in textlist.iteritems(): for verse_number, verse_text in textlist.iteritems():
verse = Verse.populate( verse = Verse.populate(
@ -300,7 +295,9 @@ class BibleDB(QtCore.QObject, Manager):
``value`` ``value``
The value for this instance. The value for this instance.
""" """
log.debug(u'save_meta %s/%s', key, value) if not isinstance(value, unicode):
value = unicode(value)
log.debug(u'BibleDB.save_meta("%s/%s")', key, value)
self.save_object(BibleMeta.populate(key=key, value=value)) self.save_object(BibleMeta.populate(key=key, value=value))
def get_book(self, book): def get_book(self, book):
@ -310,20 +307,60 @@ class BibleDB(QtCore.QObject, Manager):
``book`` ``book``
The name of the book to return. The name of the book to return.
""" """
log.debug(u'BibleDb.get_book("%s")', book) log.debug(u'BibleDB.get_book("%s")', book)
db_book = self.get_object_filtered(Book, Book.name.like(book + u'%')) return self.get_object_filtered(Book, Book.name.like(book + u'%'))
if db_book is None:
db_book = self.get_object_filtered(Book,
Book.abbreviation.like(book + u'%'))
return db_book
def get_books(self): def get_books(self):
""" """
A wrapper so both local and web bibles have a get_books() method that A wrapper so both local and web bibles have a get_books() method that
manager can call. Used in the media manager advanced search tab. manager can call. Used in the media manager advanced search tab.
""" """
log.debug(u'BibleDB.get_books()')
return self.get_all_objects(Book, order_by_ref=Book.id) return self.get_all_objects(Book, order_by_ref=Book.id)
def get_book_by_book_ref_id(self, id):
"""
Return a book object from the database.
``id``
The reference id of the book to return.
"""
log.debug(u'BibleDB.get_book_by_book_ref_id("%s")', id)
return self.get_object_filtered(Book, Book.book_reference_id.like(id))
def get_book_ref_id_by_name(self, book, maxbooks, language_id=None):
log.debug(u'BibleDB.get_book_ref_id_by_name:("%s", "%s")', book,
language_id)
if BiblesResourcesDB.get_book(book, True):
book_temp = BiblesResourcesDB.get_book(book, True)
book_id = book_temp[u'id']
elif BiblesResourcesDB.get_alternative_book_name(book):
book_id = BiblesResourcesDB.get_alternative_book_name(book)
elif AlternativeBookNamesDB.get_book_reference_id(book):
book_id = AlternativeBookNamesDB.get_book_reference_id(book)
else:
from openlp.plugins.bibles.forms import BookNameForm
book_ref = None
book_name = BookNameForm(self.wizard)
if book_name.exec_(book, self.get_books(), maxbooks):
book_ref = unicode(
book_name.correspondingComboBox.currentText())
if not book_ref:
return None
else:
book_temp = BiblesResourcesDB.get_book(book_ref)
if book_temp:
book_id = book_temp[u'id']
else:
return None
if book_id:
AlternativeBookNamesDB.create_alternative_book_name(
book, book_id, language_id)
if book_id:
return book_id
else:
return None
def get_verses(self, reference_list, show_error=True): def get_verses(self, reference_list, show_error=True):
""" """
This is probably the most used function. It retrieves the list of This is probably the most used function. It retrieves the list of
@ -333,24 +370,25 @@ class BibleDB(QtCore.QObject, Manager):
This is the list of references the media manager item wants. It is This is the list of references the media manager item wants. It is
a list of tuples, with the following format:: a list of tuples, with the following format::
(book, chapter, start_verse, end_verse) (book_reference_id, chapter, start_verse, end_verse)
Therefore, when you are looking for multiple items, simply break Therefore, when you are looking for multiple items, simply break
them up into references like this, bundle them into a list. This them up into references like this, bundle them into a list. This
function then runs through the list, and returns an amalgamated function then runs through the list, and returns an amalgamated
list of ``Verse`` objects. For example:: list of ``Verse`` objects. For example::
[(u'Genesis', 1, 1, 1), (u'Genesis', 2, 2, 3)] [(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
""" """
log.debug(u'BibleDB.get_verses: %s', reference_list) log.debug(u'BibleDB.get_verses("%s")', reference_list)
verse_list = [] verse_list = []
for book, chapter, start_verse, end_verse in reference_list: book_error = False
db_book = self.get_book(book) for book_id, chapter, start_verse, end_verse in reference_list:
db_book = self.get_book_by_book_ref_id(book_id)
if db_book: if db_book:
book = db_book.name book_id = db_book.book_reference_id
log.debug(u'Book name corrected to "%s"', book) log.debug(u'Book name corrected to "%s"', db_book.name)
if end_verse == -1: if end_verse == -1:
end_verse = self.get_verse_count(book, chapter) end_verse = self.get_verse_count(book_id, chapter)
verses = self.session.query(Verse)\ verses = self.session.query(Verse)\
.filter_by(book_id=db_book.id)\ .filter_by(book_id=db_book.id)\
.filter_by(chapter=chapter)\ .filter_by(chapter=chapter)\
@ -360,8 +398,9 @@ class BibleDB(QtCore.QObject, Manager):
.all() .all()
verse_list.extend(verses) verse_list.extend(verses)
else: else:
log.debug(u'OpenLP failed to find book %s', book) log.debug(u'OpenLP failed to find book with id "%s"', book_id)
if show_error: book_error = True
if book_error and show_error:
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'), translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching book ' translate('BiblesPlugin', 'No matching book '
@ -399,18 +438,18 @@ class BibleDB(QtCore.QObject, Manager):
Return the number of chapters in a book. Return the number of chapters in a book.
``book`` ``book``
The book to get the chapter count for. The book object to get the chapter count for.
""" """
log.debug(u'BibleDB.get_chapter_count("%s")', book) log.debug(u'BibleDB.get_chapter_count("%s")', book.name)
count = self.session.query(Verse.chapter).join(Book)\ count = self.session.query(Verse.chapter).join(Book)\
.filter(Book.name == book)\ .filter(Book.book_reference_id==book.book_reference_id)\
.distinct().count() .distinct().count()
if not count: if not count:
return 0 return 0
else: else:
return count return count
def get_verse_count(self, book, chapter): def get_verse_count(self, book_id, chapter):
""" """
Return the number of verses in a chapter. Return the number of verses in a chapter.
@ -420,9 +459,9 @@ class BibleDB(QtCore.QObject, Manager):
``chapter`` ``chapter``
The chapter to get the verse count for. The chapter to get the verse count for.
""" """
log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter) log.debug(u'BibleDB.get_verse_count("%s", "%s")', book_id, chapter)
count = self.session.query(Verse).join(Book)\ count = self.session.query(Verse).join(Book)\
.filter(Book.name == book)\ .filter(Book.book_reference_id==book_id)\
.filter(Verse.chapter==chapter)\ .filter(Verse.chapter==chapter)\
.count() .count()
if not count: if not count:
@ -430,6 +469,39 @@ class BibleDB(QtCore.QObject, Manager):
else: else:
return count return count
def get_language(self, bible_name=None):
"""
If no language is given it calls a dialog window where the user could
select the bible language.
Return the language id of a bible.
``book``
The language the bible is.
"""
log.debug(u'BibleDB.get_language()')
from openlp.plugins.bibles.forms import LanguageForm
language = None
language_form = LanguageForm(self.wizard)
if language_form.exec_(bible_name):
language = unicode(language_form.languageComboBox.currentText())
if not language:
return False
language = BiblesResourcesDB.get_language(language)
language_id = language[u'id']
self.create_meta(u'language_id', language_id)
return language_id
def is_old_database(self):
"""
Returns ``True`` if it is a bible database, which has been created
prior to 1.9.6.
"""
try:
columns = self.session.query(Book).all()
except:
return True
return False
def dump_bible(self): def dump_bible(self):
""" """
Utility debugging method to dump the contents of a bible. Utility debugging method to dump the contents of a bible.
@ -441,3 +513,591 @@ class BibleDB(QtCore.QObject, Manager):
log.debug(u'...............................Verses ') log.debug(u'...............................Verses ')
verses = self.session.query(Verse).all() verses = self.session.query(Verse).all()
log.debug(verses) log.debug(verses)
class BiblesResourcesDB(QtCore.QObject, Manager):
"""
This class represents the database-bound Bible Resources. It provide
some resources which are used in the Bibles plugin.
A wrapper class around a small SQLite database which contains the download
resources, a biblelist from the different download resources, the books,
chapter counts and verse counts for the web download Bibles, a language
reference, the testament reference and some alternative book names. This
class contains a singleton "cursor" so that only one connection to the
SQLite database is ever used.
"""
cursor = None
@staticmethod
def get_cursor():
"""
Return the cursor object. Instantiate one if it doesn't exist yet.
"""
if BiblesResourcesDB.cursor is None:
filepath = os.path.join(
AppLocation.get_directory(AppLocation.PluginsDir), u'bibles',
u'resources', u'bibles_resources.sqlite')
conn = sqlite3.connect(filepath)
BiblesResourcesDB.cursor = conn.cursor()
return BiblesResourcesDB.cursor
@staticmethod
def run_sql(query, parameters=()):
"""
Run an SQL query on the database, returning the results.
``query``
The actual SQL query to run.
``parameters``
Any variable parameters to add to the query.
"""
cursor = BiblesResourcesDB.get_cursor()
cursor.execute(query, parameters)
return cursor.fetchall()
@staticmethod
def get_books():
"""
Return a list of all the books of the Bible.
"""
log.debug(u'BiblesResourcesDB.get_books()')
books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation, chapters FROM book_reference ORDER BY id')
return [
{
u'id': book[0],
u'testament_id': book[1],
u'name': unicode(book[2]),
u'abbreviation': unicode(book[3]),
u'chapters': book[4]
}
for book in books
]
@staticmethod
def get_book(name, lower=False):
"""
Return a book by name or abbreviation.
``name``
The name or abbreviation of the book.
``lower``
True if the comparsion should be only lowercase
"""
log.debug(u'BiblesResourcesDB.get_book("%s")', name)
if not isinstance(name, unicode):
name = unicode(name)
if lower:
books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation, chapters FROM book_reference WHERE '
u'LOWER(name) = ? OR LOWER(abbreviation) = ?',
(name.lower(), name.lower()))
else:
books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation, chapters FROM book_reference WHERE name = ?'
u' OR abbreviation = ?', (name, name))
if books:
return {
u'id': books[0][0],
u'testament_id': books[0][1],
u'name': unicode(books[0][2]),
u'abbreviation': unicode(books[0][3]),
u'chapters': books[0][4]
}
else:
return None
@staticmethod
def get_book_by_id(id):
"""
Return a book by id.
``id``
The id of the book.
"""
log.debug(u'BiblesResourcesDB.get_book_by_id("%s")', id)
if not isinstance(id, int):
id = int(id)
books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation, chapters FROM book_reference WHERE id = ?',
(id, ))
if books:
return {
u'id': books[0][0],
u'testament_id': books[0][1],
u'name': unicode(books[0][2]),
u'abbreviation': unicode(books[0][3]),
u'chapters': books[0][4]
}
else:
return None
@staticmethod
def get_chapter(book_id, chapter):
"""
Return the chapter details for a specific chapter of a book.
``book_id``
The id of a book.
``chapter``
The chapter number.
"""
log.debug(u'BiblesResourcesDB.get_chapter("%s", "%s")', book_id,
chapter)
if not isinstance(chapter, int):
chapter = int(chapter)
chapters = BiblesResourcesDB.run_sql(u'SELECT id, book_reference_id, '
u'chapter, verse_count FROM chapters WHERE book_reference_id = ?',
(book_id,))
if chapters:
return {
u'id': chapters[chapter-1][0],
u'book_reference_id': chapters[chapter-1][1],
u'chapter': chapters[chapter-1][2],
u'verse_count': chapters[chapter-1][3]
}
else:
return None
@staticmethod
def get_chapter_count(book_id):
"""
Return the number of chapters in a book.
``book_id``
The id of the book.
"""
log.debug(u'BiblesResourcesDB.get_chapter_count("%s")', book_id)
details = BiblesResourcesDB.get_book_by_id(book_id)
if details:
return details[u'chapters']
return 0
@staticmethod
def get_verse_count(book_id, chapter):
"""
Return the number of verses in a chapter.
``book``
The id of the book.
``chapter``
The number of the chapter.
"""
log.debug(u'BiblesResourcesDB.get_verse_count("%s", "%s")', book_id,
chapter)
details = BiblesResourcesDB.get_chapter(book_id, chapter)
if details:
return details[u'verse_count']
return 0
@staticmethod
def get_download_source(source):
"""
Return a download_source_id by source.
``name``
The name or abbreviation of the book.
"""
log.debug(u'BiblesResourcesDB.get_download_source("%s")', source)
if not isinstance(source, unicode):
source = unicode(source)
source = source.title()
dl_source = BiblesResourcesDB.run_sql(u'SELECT id, source FROM '
u'download_source WHERE source = ?', (source.lower(),))
if dl_source:
return {
u'id': dl_source[0][0],
u'source': dl_source[0][1]
}
else:
return None
@staticmethod
def get_webbibles(source):
"""
Return the bibles a webbible provide for download.
``source``
The source of the webbible.
"""
log.debug(u'BiblesResourcesDB.get_webbibles("%s")', source)
if not isinstance(source, unicode):
source = unicode(source)
source = BiblesResourcesDB.get_download_source(source)
bibles = BiblesResourcesDB.run_sql(u'SELECT id, name, abbreviation, '
u'language_id, download_source_id FROM webbibles WHERE '
u'download_source_id = ?', (source[u'id'],))
if bibles:
return [
{
u'id': bible[0],
u'name': bible[1],
u'abbreviation': bible[2],
u'language_id': bible[3],
u'download_source_id': bible[4]
}
for bible in bibles
]
else:
return None
@staticmethod
def get_webbible(abbreviation, source):
"""
Return the bibles a webbible provide for download.
``abbreviation``
The abbreviation of the webbible.
``source``
The source of the webbible.
"""
log.debug(u'BiblesResourcesDB.get_webbibles("%s", "%s")', abbreviation,
source)
if not isinstance(abbreviation, unicode):
abbreviation = unicode(abbreviation)
if not isinstance(source, unicode):
source = unicode(source)
source = BiblesResourcesDB.get_download_source(source)
bible = BiblesResourcesDB.run_sql(u'SELECT id, name, abbreviation, '
u'language_id, download_source_id FROM webbibles WHERE '
u'download_source_id = ? AND abbreviation = ?', (source[u'id'],
abbreviation))
if bible:
return {
u'id': bible[0][0],
u'name': bible[0][1],
u'abbreviation': bible[0][2],
u'language_id': bible[0][3],
u'download_source_id': bible[0][4]
}
else:
return None
@staticmethod
def get_alternative_book_name(name, language_id=None):
"""
Return a book_reference_id if the name matches.
``name``
The name to search the id.
``language_id``
The language_id for which language should be searched
"""
log.debug(u'BiblesResourcesDB.get_alternative_book_name("%s", "%s")',
name, language_id)
if language_id:
books = BiblesResourcesDB.run_sql(u'SELECT book_reference_id, name '
u'FROM alternative_book_names WHERE language_id = ? ORDER BY '
u'id', (language_id, ))
else:
books = BiblesResourcesDB.run_sql(u'SELECT book_reference_id, name '
u'FROM alternative_book_names ORDER BY id')
for book in books:
if book[1].lower() == name.lower():
return book[0]
return None
@staticmethod
def get_language(name):
"""
Return a dict containing the language id, name and code by name or
abbreviation.
``name``
The name or abbreviation of the language.
"""
log.debug(u'BiblesResourcesDB.get_language("%s")', name)
if not isinstance(name, unicode):
name = unicode(name)
language = BiblesResourcesDB.run_sql(u'SELECT id, name, code FROM '
u'language WHERE name = ? OR code = ?', (name, name.lower()))
if language:
return {
u'id': language[0][0],
u'name': unicode(language[0][1]),
u'code': unicode(language[0][2])
}
else:
return None
@staticmethod
def get_languages():
"""
Return a dict containing all languages with id, name and code.
"""
log.debug(u'BiblesResourcesDB.get_languages()')
languages = BiblesResourcesDB.run_sql(u'SELECT id, name, code FROM '
u'language ORDER by name')
if languages:
return [
{
u'id': language[0],
u'name': unicode(language[1]),
u'code': unicode(language[2])
}
for language in languages
]
else:
return None
@staticmethod
def get_testament_reference():
"""
Return a list of all testaments and their id of the Bible.
"""
log.debug(u'BiblesResourcesDB.get_testament_reference()')
testaments = BiblesResourcesDB.run_sql(u'SELECT id, name FROM '
u'testament_reference ORDER BY id')
return [
{
u'id': testament[0],
u'name': unicode(testament[1])
}
for testament in testaments
]
class AlternativeBookNamesDB(QtCore.QObject, Manager):
"""
This class represents a database-bound alternative book names system.
"""
cursor = None
conn = None
@staticmethod
def get_cursor():
"""
Return the cursor object. Instantiate one if it doesn't exist yet.
If necessary loads up the database and creates the tables if the
database doesn't exist.
"""
if AlternativeBookNamesDB.cursor is None:
filepath = os.path.join(
AppLocation.get_directory(AppLocation.DataDir), u'bibles',
u'alternative_book_names.sqlite')
if not os.path.exists(filepath):
#create new DB, create table alternative_book_names
AlternativeBookNamesDB.conn = sqlite3.connect(filepath)
AlternativeBookNamesDB.conn.execute(u'CREATE TABLE '
u'alternative_book_names(id INTEGER NOT NULL, '
u'book_reference_id INTEGER, language_id INTEGER, name '
u'VARCHAR(50), PRIMARY KEY (id))')
else:
#use existing DB
AlternativeBookNamesDB.conn = sqlite3.connect(filepath)
AlternativeBookNamesDB.cursor = AlternativeBookNamesDB.conn.cursor()
return AlternativeBookNamesDB.cursor
@staticmethod
def run_sql(query, parameters=(), commit=None):
"""
Run an SQL query on the database, returning the results.
``query``
The actual SQL query to run.
``parameters``
Any variable parameters to add to the query
``commit``
If a commit statement is necessary this should be True.
"""
cursor = AlternativeBookNamesDB.get_cursor()
cursor.execute(query, parameters)
if commit:
AlternativeBookNamesDB.conn.commit()
return cursor.fetchall()
@staticmethod
def get_book_reference_id(name, language_id=None):
"""
Return a book_reference_id if the name matches.
``name``
The name to search the id.
``language_id``
The language_id for which language should be searched
"""
log.debug(u'AlternativeBookNamesDB.get_book_reference_id("%s", "%s")',
name, language_id)
if language_id:
books = AlternativeBookNamesDB.run_sql(u'SELECT book_reference_id, '
u'name FROM alternative_book_names WHERE language_id = ?',
(language_id, ))
else:
books = AlternativeBookNamesDB.run_sql(u'SELECT book_reference_id, '
u'name FROM alternative_book_names')
for book in books:
if book[1].lower() == name.lower():
return book[0]
return None
@staticmethod
def create_alternative_book_name(name, book_reference_id, language_id):
"""
Add an alternative book name to the database.
``name``
The name of the alternative book name.
``book_reference_id``
The book_reference_id of the book.
``language_id``
The language to which the alternative book name belong.
"""
log.debug(u'AlternativeBookNamesDB.create_alternative_book_name("%s", '
'"%s", "%s"', name, book_reference_id, language_id)
return AlternativeBookNamesDB.run_sql(u'INSERT INTO '
u'alternative_book_names(book_reference_id, language_id, name) '
u'VALUES (?, ?, ?)', (book_reference_id, language_id, name), True)
class OldBibleDB(QtCore.QObject, Manager):
"""
This class conects to the old bible databases to reimport them to the new
database scheme.
"""
cursor = None
def __init__(self, parent, **kwargs):
"""
The constructor loads up the database and creates and initialises the
tables if the database doesn't exist.
**Required keyword arguments:**
``path``
The path to the bible database file.
``name``
The name of the database. This is also used as the file name for
SQLite databases.
"""
log.info(u'OldBibleDB loaded')
QtCore.QObject.__init__(self)
if u'path' not in kwargs:
raise KeyError(u'Missing keyword argument "path".')
if u'file' not in kwargs:
raise KeyError(u'Missing keyword argument "file".')
if u'path' in kwargs:
self.path = kwargs[u'path']
if u'file' in kwargs:
self.file = kwargs[u'file']
def get_cursor(self):
"""
Return the cursor object. Instantiate one if it doesn't exist yet.
"""
if self.cursor is None:
filepath = os.path.join(self.path, self.file)
self.connection = sqlite3.connect(filepath)
self.cursor = self.connection.cursor()
return self.cursor
def run_sql(self, query, parameters=()):
"""
Run an SQL query on the database, returning the results.
``query``
The actual SQL query to run.
``parameters``
Any variable parameters to add to the query.
"""
cursor = self.get_cursor()
cursor.execute(query, parameters)
return cursor.fetchall()
def get_name(self):
"""
Returns the version name of the Bible.
"""
version_name = self.run_sql(u'SELECT value FROM '
u'metadata WHERE key = "Version"')
if version_name:
self.name = version_name[0][0]
else:
self.name = None
return self.name
def get_metadata(self):
"""
Returns the metadata of the Bible.
"""
metadata = self.run_sql(u'SELECT key, value FROM metadata '
u'ORDER BY rowid')
if metadata:
return [
{
u'key': unicode(meta[0]),
u'value': unicode(meta[1])
}
for meta in metadata
]
else:
return None
def get_book(self, name):
"""
Return a book by name or abbreviation.
``name``
The name or abbreviation of the book.
"""
if not isinstance(name, unicode):
name = unicode(name)
books = self.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation FROM book WHERE LOWER(name) = ? OR '
u'LOWER(abbreviation) = ?', (name.lower(), name.lower()))
if books:
return {
u'id': books[0][0],
u'testament_id': books[0][1],
u'name': unicode(books[0][2]),
u'abbreviation': unicode(books[0][3])
}
else:
return None
def get_books(self):
"""
Returns the books of the Bible.
"""
books = self.run_sql(u'SELECT name, id FROM book ORDER BY id')
if books:
return [
{
u'name': unicode(book[0]),
u'id':int(book[1])
}
for book in books
]
else:
return None
def get_verses(self, book_id):
"""
Returns the verses of the Bible.
"""
verses = self.run_sql(u'SELECT book_id, chapter, verse, text FROM '
u'verse WHERE book_id = ? ORDER BY id', (book_id, ))
if verses:
return [
{
u'book_id': int(verse[0]),
u'chapter': int(verse[1]),
u'verse': int(verse[2]),
u'text': unicode(verse[3])
}
for verse in verses
]
else:
return None

View File

@ -42,161 +42,26 @@ from openlp.core.lib import Receiver, translate
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import AppLocation, get_web_page from openlp.core.utils import AppLocation, get_web_page
from openlp.plugins.bibles.lib import SearchResults from openlp.plugins.bibles.lib import SearchResults
from openlp.plugins.bibles.lib.db import BibleDB, Book from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, \
Book
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class HTTPBooks(object):
"""
A wrapper class around a small SQLite database which contains the books,
chapter counts and verse counts for the web download Bibles. This class
contains a singleton "cursor" so that only one connection to the SQLite
database is ever used.
"""
cursor = None
@staticmethod
def get_cursor():
"""
Return the cursor object. Instantiate one if it doesn't exist yet.
"""
if HTTPBooks.cursor is None:
filepath = os.path.join(
AppLocation.get_directory(AppLocation.PluginsDir), u'bibles',
u'resources', u'httpbooks.sqlite')
conn = sqlite3.connect(filepath)
HTTPBooks.cursor = conn.cursor()
return HTTPBooks.cursor
@staticmethod
def run_sql(query, parameters=()):
"""
Run an SQL query on the database, returning the results.
``query``
The actual SQL query to run.
``parameters``
Any variable parameters to add to the query.
"""
cursor = HTTPBooks.get_cursor()
cursor.execute(query, parameters)
return cursor.fetchall()
@staticmethod
def get_books():
"""
Return a list of all the books of the Bible.
"""
books = HTTPBooks.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation, chapters FROM books ORDER BY id')
book_list = []
for book in books:
book_list.append({
u'id': book[0],
u'testament_id': book[1],
u'name': unicode(book[2]),
u'abbreviation': unicode(book[3]),
u'chapters': book[4]
})
return book_list
@staticmethod
def get_book(name):
"""
Return a book by name or abbreviation.
``name``
The name or abbreviation of the book.
"""
if not isinstance(name, unicode):
name = unicode(name)
name = name.title()
books = HTTPBooks.run_sql(u'SELECT id, testament_id, name, '
u'abbreviation, chapters FROM books WHERE name = ? OR '
u'abbreviation = ?', (name, name))
if books:
return {
u'id': books[0][0],
u'testament_id': books[0][1],
u'name': unicode(books[0][2]),
u'abbreviation': unicode(books[0][3]),
u'chapters': books[0][4]
}
else:
return None
@staticmethod
def get_chapter(name, chapter):
"""
Return the chapter details for a specific chapter of a book.
``name``
The name or abbreviation of a book.
``chapter``
The chapter number.
"""
if not isinstance(name, int):
chapter = int(chapter)
book = HTTPBooks.get_book(name)
chapters = HTTPBooks.run_sql(u'SELECT id, book_id, chapter, '
u'verses FROM chapters WHERE book_id = ?', (book[u'id'],))
if chapters:
return {
u'id': chapters[chapter-1][0],
u'book_id': chapters[chapter-1][1],
u'chapter': chapters[chapter-1][2],
u'verses': chapters[chapter-1][3]
}
else:
return None
@staticmethod
def get_chapter_count(book):
"""
Return the number of chapters in a book.
``book``
The name or abbreviation of the book.
"""
details = HTTPBooks.get_book(book)
if details:
return details[u'chapters']
return 0
@staticmethod
def get_verse_count(book, chapter):
"""
Return the number of verses in a chapter.
``book``
The name or abbreviation of the book.
``chapter``
The number of the chapter.
"""
details = HTTPBooks.get_chapter(book, chapter)
if details:
return details[u'verses']
return 0
class BGExtract(object): class BGExtract(object):
""" """
Extract verses from BibleGateway Extract verses from BibleGateway
""" """
def __init__(self, proxyurl=None): def __init__(self, proxyurl=None):
log.debug(u'init %s', proxyurl) log.debug(u'BGExtract.init("%s")', proxyurl)
self.proxyurl = proxyurl self.proxyurl = proxyurl
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
def get_bible_chapter(self, version, bookname, chapter): def get_bible_chapter(self, version, bookname, chapter):
""" """
Access and decode bibles via the BibleGateway website. Access and decode Bibles via the BibleGateway website.
``version`` ``version``
The version of the bible like 31 for New International version. The version of the Bible like 31 for New International version.
``bookname`` ``bookname``
Name of the Book. Name of the Book.
@ -204,10 +69,11 @@ class BGExtract(object):
``chapter`` ``chapter``
Chapter number. Chapter number.
""" """
log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter) log.debug(u'BGExtract.get_bible_chapter("%s", "%s", "%s")', version,
url_params = urllib.urlencode( bookname, chapter)
{u'search': u'%s %s' % (bookname, chapter), urlbookname = urllib.quote(bookname.encode("utf-8"))
u'version': u'%s' % version}) url_params = u'search=%s+%s&version=%s' % (urlbookname, chapter,
version)
cleaner = [(re.compile('&nbsp;|<br />|\'\+\''), lambda match: '')] cleaner = [(re.compile('&nbsp;|<br />|\'\+\''), lambda match: '')]
soup = get_soup_for_bible_ref( soup = get_soup_for_bible_ref(
u'http://www.biblegateway.com/passage/?%s' % url_params, u'http://www.biblegateway.com/passage/?%s' % url_params,
@ -230,7 +96,7 @@ class BGExtract(object):
verse_list = {} verse_list = {}
# Cater for inconsistent mark up in the first verse of a chapter. # Cater for inconsistent mark up in the first verse of a chapter.
first_verse = verses.find(u'versenum') first_verse = verses.find(u'versenum')
if first_verse: if first_verse and len(first_verse.contents):
verse_list[1] = unicode(first_verse.contents[0]) verse_list[1] = unicode(first_verse.contents[0])
for verse in verses(u'sup', u'versenum'): for verse in verses(u'sup', u'versenum'):
raw_verse_num = verse.next raw_verse_num = verse.next
@ -243,7 +109,7 @@ class BGExtract(object):
try: try:
clean_verse_num = int(str(raw_verse_num)) clean_verse_num = int(str(raw_verse_num))
except ValueError: except ValueError:
log.exception(u'Illegal verse number in %s %s %s:%s', log.warn(u'Illegal verse number in %s %s %s:%s',
version, bookname, chapter, unicode(raw_verse_num)) version, bookname, chapter, unicode(raw_verse_num))
if clean_verse_num: if clean_verse_num:
verse_text = raw_verse_num.next verse_text = raw_verse_num.next
@ -264,13 +130,60 @@ class BGExtract(object):
return None return None
return SearchResults(bookname, chapter, verse_list) return SearchResults(bookname, chapter, verse_list)
def get_books_from_http(self, version):
"""
Load a list of all books a Bible contaions from BibleGateway website.
``version``
The version of the Bible like NIV for New International Version
"""
log.debug(u'BGExtract.get_books_from_http("%s")', version)
url_params = urllib.urlencode(
{u'action': 'getVersionInfo', u'vid': u'%s' % version})
reference_url = u'http://www.biblegateway.com/versions/?%s#books' % \
url_params
page = get_web_page(reference_url)
if not page:
send_error_message(u'download')
return None
page_source = page.read()
page_source = unicode(page_source, 'utf8')
page_source_temp = re.search(u'<table .*?class="infotable".*?>.*?'\
u'</table>', page_source, re.DOTALL)
if page_source_temp:
soup = page_source_temp.group(0)
else:
soup = None
try:
soup = BeautifulSoup(soup)
except HTMLParseError:
log.error(u'BeautifulSoup could not parse the Bible page.')
send_error_message(u'parse')
return None
if not soup:
send_error_message(u'parse')
return None
Receiver.send_message(u'openlp_process_events')
content = soup.find(u'table', {u'class': u'infotable'})
content = content.findAll(u'tr')
if not content:
log.error(u'No books found in the Biblegateway response.')
send_error_message(u'parse')
return None
books = []
for book in content:
book = book.find(u'td')
if book:
books.append(book.contents[0])
return books
class BSExtract(object): class BSExtract(object):
""" """
Extract verses from Bibleserver.com Extract verses from Bibleserver.com
""" """
def __init__(self, proxyurl=None): def __init__(self, proxyurl=None):
log.debug(u'init %s', proxyurl) log.debug(u'BSExtract.init("%s")', proxyurl)
self.proxyurl = proxyurl self.proxyurl = proxyurl
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
@ -287,9 +200,12 @@ class BSExtract(object):
``chapter`` ``chapter``
Chapter number Chapter number
""" """
log.debug(u'get_bible_chapter %s,%s,%s', version, bookname, chapter) log.debug(u'BSExtract.get_bible_chapter("%s", "%s", "%s")', version,
chapter_url = u'http://m.bibleserver.com/text/%s/%s%s' % \ bookname, chapter)
(version, bookname, chapter) urlversion = urllib.quote(version.encode("utf-8"))
urlbookname = urllib.quote(bookname.encode("utf-8"))
chapter_url = u'http://m.bibleserver.com/text/%s/%s%d' % \
(urlversion, urlbookname, chapter)
header = (u'Accept-Language', u'en') header = (u'Accept-Language', u'en')
soup = get_soup_for_bible_ref(chapter_url, header) soup = get_soup_for_bible_ref(chapter_url, header)
if not soup: if not soup:
@ -297,7 +213,7 @@ class BSExtract(object):
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
content = soup.find(u'div', u'content') content = soup.find(u'div', u'content')
if not content: if not content:
log.exception(u'No verses found in the Bibleserver response.') log.error(u'No verses found in the Bibleserver response.')
send_error_message(u'parse') send_error_message(u'parse')
return None return None
content = content.find(u'div').findAll(u'div') content = content.find(u'div').findAll(u'div')
@ -309,13 +225,38 @@ class BSExtract(object):
verses[versenumber] = verse.contents[1].rstrip(u'\n') verses[versenumber] = verse.contents[1].rstrip(u'\n')
return SearchResults(bookname, chapter, verses) return SearchResults(bookname, chapter, verses)
def get_books_from_http(self, version):
"""
Load a list of all books a Bible contains from Bibleserver mobile
website.
``version``
The version of the Bible like NIV for New International Version
"""
log.debug(u'BSExtract.get_books_from_http("%s")', version)
urlversion = urllib.quote(version.encode("utf-8"))
chapter_url = u'http://m.bibleserver.com/overlay/selectBook?'\
'translation=%s' % (urlversion)
soup = get_soup_for_bible_ref(chapter_url)
if not soup:
return None
content = soup.find(u'ul')
if not content:
log.error(u'No books found in the Bibleserver response.')
send_error_message(u'parse')
return None
content = content.findAll(u'li')
return [
book.contents[0].contents[0] for book in content
]
class CWExtract(object): class CWExtract(object):
""" """
Extract verses from CrossWalk/BibleStudyTools Extract verses from CrossWalk/BibleStudyTools
""" """
def __init__(self, proxyurl=None): def __init__(self, proxyurl=None):
log.debug(u'init %s', proxyurl) log.debug(u'CWExtract.init("%s")', proxyurl)
self.proxyurl = proxyurl self.proxyurl = proxyurl
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
@ -324,7 +265,7 @@ class CWExtract(object):
Access and decode bibles via the Crosswalk website Access and decode bibles via the Crosswalk website
``version`` ``version``
The version of the bible like niv for New International Version The version of the Bible like niv for New International Version
``bookname`` ``bookname``
Text name of in english e.g. 'gen' for Genesis Text name of in english e.g. 'gen' for Genesis
@ -332,17 +273,20 @@ class CWExtract(object):
``chapter`` ``chapter``
Chapter number Chapter number
""" """
log.debug(u'get_bible_chapter %s,%s,%s', version, bookname, chapter) log.debug(u'CWExtract.get_bible_chapter("%s", "%s", "%s")', version,
bookname, chapter)
urlbookname = bookname.replace(u' ', u'-') urlbookname = bookname.replace(u' ', u'-')
urlbookname = urlbookname.lower()
urlbookname = urllib.quote(urlbookname.encode("utf-8"))
chapter_url = u'http://www.biblestudytools.com/%s/%s/%s.html' % \ chapter_url = u'http://www.biblestudytools.com/%s/%s/%s.html' % \
(version, urlbookname.lower(), chapter) (version, urlbookname, chapter)
soup = get_soup_for_bible_ref(chapter_url) soup = get_soup_for_bible_ref(chapter_url)
if not soup: if not soup:
return None return None
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
htmlverses = soup.findAll(u'span', u'versetext') htmlverses = soup.findAll(u'span', u'versetext')
if not htmlverses: if not htmlverses:
log.debug(u'No verses found in the CrossWalk response.') log.error(u'No verses found in the CrossWalk response.')
send_error_message(u'parse') send_error_message(u'parse')
return None return None
verses = {} verses = {}
@ -378,6 +322,32 @@ class CWExtract(object):
verses[versenumber] = versetext verses[versenumber] = versetext
return SearchResults(bookname, chapter, verses) return SearchResults(bookname, chapter, verses)
def get_books_from_http(self, version):
"""
Load a list of all books a Bible contain from the Crosswalk website.
``version``
The version of the bible like NIV for New International Version
"""
log.debug(u'CWExtract.get_books_from_http("%s")', version)
chapter_url = u'http://www.biblestudytools.com/%s/'\
% (version)
soup = get_soup_for_bible_ref(chapter_url)
if not soup:
return None
content = soup.find(u'div', {u'class': u'Body'})
content = content.find(u'ul', {u'class': u'parent'})
if not content:
log.error(u'No books found in the Crosswalk response.')
send_error_message(u'parse')
return None
content = content.findAll(u'li')
books = []
for book in content:
book = book.find(u'a')
books.append(book.contents[0])
return books
class HTTPBible(BibleDB): class HTTPBible(BibleDB):
log.info(u'%s HTTPBible loaded' , __name__) log.info(u'%s HTTPBible loaded' , __name__)
@ -400,6 +370,8 @@ class HTTPBible(BibleDB):
self.proxy_server = None self.proxy_server = None
self.proxy_username = None self.proxy_username = None
self.proxy_password = None self.proxy_password = None
if u'path' in kwargs:
self.path = kwargs[u'path']
if u'proxy_server' in kwargs: if u'proxy_server' in kwargs:
self.proxy_server = kwargs[u'proxy_server'] self.proxy_server = kwargs[u'proxy_server']
if u'proxy_username' in kwargs: if u'proxy_username' in kwargs:
@ -407,13 +379,15 @@ class HTTPBible(BibleDB):
if u'proxy_password' in kwargs: if u'proxy_password' in kwargs:
self.proxy_password = kwargs[u'proxy_password'] self.proxy_password = kwargs[u'proxy_password']
def do_import(self): def do_import(self, bible_name=None):
""" """
Run the import. This method overrides the parent class method. Returns Run the import. This method overrides the parent class method. Returns
``True`` on success, ``False`` on failure. ``True`` on success, ``False`` on failure.
""" """
self.wizard.progressBar.setMaximum(2) self.wizard.progressBar.setMaximum(68)
self.wizard.incrementProgressBar('Registering bible...') self.wizard.incrementProgressBar(unicode(translate(
'BiblesPlugin.HTTPBible',
'Registering Bible and loading books...')))
self.create_meta(u'download source', self.download_source) self.create_meta(u'download source', self.download_source)
self.create_meta(u'download name', self.download_name) self.create_meta(u'download name', self.download_name)
if self.proxy_server: if self.proxy_server:
@ -424,6 +398,50 @@ class HTTPBible(BibleDB):
if self.proxy_password: if self.proxy_password:
# Store the proxy password. # Store the proxy password.
self.create_meta(u'proxy password', self.proxy_password) self.create_meta(u'proxy password', self.proxy_password)
if self.download_source.lower() == u'crosswalk':
handler = CWExtract(self.proxy_server)
elif self.download_source.lower() == u'biblegateway':
handler = BGExtract(self.proxy_server)
elif self.download_source.lower() == u'bibleserver':
handler = BSExtract(self.proxy_server)
books = handler.get_books_from_http(self.download_name)
if not books:
log.exception(u'Importing books from %s - download name: "%s" '\
'failed' % (self.download_source, self.download_name))
return False
self.wizard.progressBar.setMaximum(len(books)+2)
self.wizard.incrementProgressBar(unicode(translate(
'BiblesPlugin.HTTPBible', 'Registering Language...')))
bible = BiblesResourcesDB.get_webbible(self.download_name,
self.download_source.lower())
if bible[u'language_id']:
language_id = bible[u'language_id']
self.create_meta(u'language_id', language_id)
else:
language_id = self.get_language(bible_name)
if not language_id:
log.exception(u'Importing books from %s " '\
'failed' % self.filename)
return False
for book in books:
if self.stop_import_flag:
break
self.wizard.incrementProgressBar(unicode(translate(
'BiblesPlugin.HTTPBible', 'Importing %s...',
'Importing <book name>...')) % book)
book_ref_id = self.get_book_ref_id_by_name(book, len(books),
language_id)
if not book_ref_id:
log.exception(u'Importing books from %s - download name: "%s" '\
'failed' % (self.download_source, self.download_name))
return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
log.debug(u'Book details: Name:%s; id:%s; testament_id:%s',
book, book_ref_id, book_details[u'testament_id'])
self.create_book(book, book_ref_id, book_details[u'testament_id'])
if self.stop_import_flag:
return False
else:
return True return True
def get_verses(self, reference_list, show_error=True): def get_verses(self, reference_list, show_error=True):
@ -438,22 +456,20 @@ class HTTPBible(BibleDB):
This is the list of references the media manager item wants. It is This is the list of references the media manager item wants. It is
a list of tuples, with the following format:: a list of tuples, with the following format::
(book, chapter, start_verse, end_verse) (book_reference_id, chapter, start_verse, end_verse)
Therefore, when you are looking for multiple items, simply break Therefore, when you are looking for multiple items, simply break
them up into references like this, bundle them into a list. This them up into references like this, bundle them into a list. This
function then runs through the list, and returns an amalgamated function then runs through the list, and returns an amalgamated
list of ``Verse`` objects. For example:: list of ``Verse`` objects. For example::
[(u'Genesis', 1, 1, 1), (u'Genesis', 2, 2, 3)] [(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
""" """
log.debug(u'HTTPBible.get_verses("%s")', reference_list)
for reference in reference_list: for reference in reference_list:
log.debug(u'Reference: %s', reference) book_id = reference[0]
book = reference[0] db_book = self.get_book_by_book_ref_id(book_id)
db_book = self.get_book(book)
if not db_book: if not db_book:
book_details = HTTPBooks.get_book(book)
if not book_details:
if show_error: if show_error:
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'), translate('BiblesPlugin', 'No Book Found'),
@ -461,11 +477,8 @@ class HTTPBible(BibleDB):
'book could be found in this Bible. Check that you ' 'book could be found in this Bible. Check that you '
'have spelled the name of the book correctly.')) 'have spelled the name of the book correctly.'))
return [] return []
db_book = self.create_book(book_details[u'name'],
book_details[u'abbreviation'],
book_details[u'testament_id'])
book = db_book.name book = db_book.name
if BibleDB.get_verse_count(self, book, reference[1]) == 0: if BibleDB.get_verse_count(self, book_id, reference[1]) == 0:
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
search_results = self.get_chapter(book, reference[1]) search_results = self.get_chapter(book, reference[1])
if search_results and search_results.has_verselist(): if search_results and search_results.has_verselist():
@ -488,7 +501,7 @@ class HTTPBible(BibleDB):
""" """
Receive the request and call the relevant handler methods. Receive the request and call the relevant handler methods.
""" """
log.debug(u'get_chapter %s, %s', book, chapter) log.debug(u'HTTPBible.get_chapter("%s", "%s")', book, chapter)
log.debug(u'source = %s', self.download_source) log.debug(u'source = %s', self.download_source)
if self.download_source.lower() == u'crosswalk': if self.download_source.lower() == u'crosswalk':
handler = CWExtract(self.proxy_server) handler = CWExtract(self.proxy_server)
@ -502,16 +515,20 @@ class HTTPBible(BibleDB):
""" """
Return the list of books. Return the list of books.
""" """
return [Book.populate(name=book['name']) log.debug(u'HTTPBible.get_books("%s")', Book.name)
for book in HTTPBooks.get_books()] return self.get_all_objects(Book, order_by_ref=Book.id)
def get_chapter_count(self, book): def get_chapter_count(self, book):
""" """
Return the number of chapters in a particular book. Return the number of chapters in a particular book.
"""
return HTTPBooks.get_chapter_count(book)
def get_verse_count(self, book, chapter): ``book``
The book object to get the chapter count for.
"""
log.debug(u'HTTPBible.get_chapter_count("%s")', book.name)
return BiblesResourcesDB.get_chapter_count(book.book_reference_id)
def get_verse_count(self, book_id, chapter):
""" """
Return the number of verses for the specified chapter and book. Return the number of verses for the specified chapter and book.
@ -521,7 +538,8 @@ class HTTPBible(BibleDB):
``chapter`` ``chapter``
The chapter whose verses are being counted. The chapter whose verses are being counted.
""" """
return HTTPBooks.get_verse_count(book, chapter) log.debug(u'HTTPBible.get_verse_count("%s", %s)', book_id, chapter)
return BiblesResourcesDB.get_verse_count(book_id, chapter)
def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
pre_parse_substitute=None, cleaner=None): pre_parse_substitute=None, cleaner=None):

View File

@ -31,9 +31,10 @@ import os
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.lib import Receiver, SettingsManager, translate from openlp.core.lib import Receiver, SettingsManager, translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import AppLocation, delete_file from openlp.core.utils import AppLocation, delete_file
from openlp.plugins.bibles.lib import parse_reference from openlp.plugins.bibles.lib import parse_reference
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB
from csvbible import CSVBible from csvbible import CSVBible
from http import HTTPBible from http import HTTPBible
from opensong import OpenSongBible from opensong import OpenSongBible
@ -140,8 +141,11 @@ class BibleManager(object):
""" """
log.debug(u'Reload bibles') log.debug(u'Reload bibles')
files = SettingsManager.get_files(self.settingsSection, self.suffix) files = SettingsManager.get_files(self.settingsSection, self.suffix)
if u'alternative_book_names.sqlite' in files:
files.remove(u'alternative_book_names.sqlite')
log.debug(u'Bible Files %s', files) log.debug(u'Bible Files %s', files)
self.db_cache = {} self.db_cache = {}
self.old_bible_databases = []
for filename in files: for filename in files:
bible = BibleDB(self.parent, path=self.path, file=filename) bible = BibleDB(self.parent, path=self.path, file=filename)
name = bible.get_name() name = bible.get_name()
@ -149,6 +153,11 @@ class BibleManager(object):
if name is None: if name is None:
delete_file(os.path.join(self.path, filename)) delete_file(os.path.join(self.path, filename))
continue continue
# Find old database versions
if bible.is_old_database():
self.old_bible_databases.append([filename, name])
bible.session.close()
continue
log.debug(u'Bible Name: "%s"', name) log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible self.db_cache[name] = bible
# Look to see if lazy load bible exists and get create getter. # Look to see if lazy load bible exists and get create getter.
@ -211,7 +220,8 @@ class BibleManager(object):
return [ return [
{ {
u'name': book.name, u'name': book.name,
u'chapters': self.db_cache[bible].get_chapter_count(book.name) u'book_reference_id': book.book_reference_id,
u'chapters': self.db_cache[bible].get_chapter_count(book)
} }
for book in self.db_cache[bible].get_books() for book in self.db_cache[bible].get_books()
] ]
@ -219,8 +229,15 @@ class BibleManager(object):
def get_chapter_count(self, bible, book): def get_chapter_count(self, bible, book):
""" """
Returns the number of Chapters for a given book. Returns the number of Chapters for a given book.
``bible``
Unicode. The Bible to get the list of books from.
``book``
The book object to get the chapter count for.
""" """
log.debug(u'get_book_chapter_count %s', book) log.debug(u'BibleManager.get_book_chapter_count ("%s", "%s")', bible,
book.name)
return self.db_cache[bible].get_chapter_count(book) return self.db_cache[bible].get_chapter_count(book)
def get_verse_count(self, bible, book, chapter): def get_verse_count(self, bible, book, chapter):
@ -230,9 +247,11 @@ class BibleManager(object):
""" """
log.debug(u'BibleManager.get_verse_count("%s", "%s", %s)', log.debug(u'BibleManager.get_verse_count("%s", "%s", %s)',
bible, book, chapter) bible, book, chapter)
return self.db_cache[bible].get_verse_count(book, chapter) db_book = self.db_cache[bible].get_book(book)
book_ref_id = db_book.book_reference_id
return self.db_cache[bible].get_verse_count(book_ref_id, chapter)
def get_verses(self, bible, versetext, show_error=True): def get_verses(self, bible, versetext, firstbible=False, show_error=True):
""" """
Parses a scripture reference, fetches the verses from the Bible Parses a scripture reference, fetches the verses from the Bible
specified, and returns a list of ``Verse`` objects. specified, and returns a list of ``Verse`` objects.
@ -264,6 +283,28 @@ class BibleManager(object):
return None return None
reflist = parse_reference(versetext) reflist = parse_reference(versetext)
if reflist: if reflist:
new_reflist = []
for item in reflist:
if item:
if firstbible:
db_book = self.db_cache[firstbible].get_book(item[0])
db_book = self.db_cache[bible].get_book_by_book_ref_id(
db_book.book_reference_id)
else:
db_book = self.db_cache[bible].get_book(item[0])
if db_book:
book_id = db_book.book_reference_id
log.debug(u'Book name corrected to "%s"', db_book.name)
new_reflist.append((book_id, item[1], item[2],
item[3]))
else:
log.debug(u'OpenLP failed to find book %s', item[0])
critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching book '
'could be found in this Bible. Check that you have '
'spelled the name of the book correctly.'))
reflist = new_reflist
return self.db_cache[bible].get_verses(reflist, show_error) return self.db_cache[bible].get_verses(reflist, show_error)
else: else:
if show_error: if show_error:

View File

@ -61,7 +61,7 @@ class BibleMediaItem(MediaManagerItem):
self.unlockIcon = QtGui.QIcon(u':/bibles/bibles_search_unlock.png') self.unlockIcon = QtGui.QIcon(u':/bibles/bibles_search_unlock.png')
MediaManagerItem.__init__(self, parent, plugin, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
# Place to store the search results for both bibles. # Place to store the search results for both bibles.
self.settings = self.parent.settings_tab self.settings = self.plugin.settings_tab
self.quickPreviewAllowed = True self.quickPreviewAllowed = True
self.hasSearch = True self.hasSearch = True
self.search_results = {} self.search_results = {}
@ -239,8 +239,14 @@ class BibleMediaItem(MediaManagerItem):
self.advancedLayout.addWidget(self.advancedToVerse, 4, 2) self.advancedLayout.addWidget(self.advancedToVerse, 4, 2)
self.addSearchFields(u'advanced', UiStrings().Advanced) self.addSearchFields(u'advanced', UiStrings().Advanced)
# Combo Boxes # Combo Boxes
QtCore.QObject.connect(self.quickVersionComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onQuickVersionComboBox)
QtCore.QObject.connect(self.quickSecondComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onQuickSecondComboBox)
QtCore.QObject.connect(self.advancedVersionComboBox, QtCore.QObject.connect(self.advancedVersionComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedVersionComboBox) QtCore.SIGNAL(u'activated(int)'), self.onAdvancedVersionComboBox)
QtCore.QObject.connect(self.advancedSecondComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedSecondComboBox)
QtCore.QObject.connect(self.advancedBookComboBox, QtCore.QObject.connect(self.advancedBookComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedBookComboBox) QtCore.SIGNAL(u'activated(int)'), self.onAdvancedBookComboBox)
QtCore.QObject.connect(self.advancedFromChapter, QtCore.QObject.connect(self.advancedFromChapter,
@ -338,7 +344,7 @@ class BibleMediaItem(MediaManagerItem):
def initialise(self): def initialise(self):
log.debug(u'bible manager initialise') log.debug(u'bible manager initialise')
self.parent.manager.media = self self.plugin.manager.media = self
self.loadBibles() self.loadBibles()
bible = QtCore.QSettings().value( bible = QtCore.QSettings().value(
self.settingsSection + u'/quick bible', QtCore.QVariant( self.settingsSection + u'/quick bible', QtCore.QVariant(
@ -365,7 +371,7 @@ class BibleMediaItem(MediaManagerItem):
self.quickSecondComboBox.addItem(u'') self.quickSecondComboBox.addItem(u'')
self.advancedSecondComboBox.addItem(u'') self.advancedSecondComboBox.addItem(u'')
# Get all bibles and sort the list. # Get all bibles and sort the list.
bibles = self.parent.manager.get_bibles().keys() bibles = self.plugin.manager.get_bibles().keys()
bibles.sort(cmp=locale.strcoll) bibles.sort(cmp=locale.strcoll)
# Load the bibles into the combo boxes. # Load the bibles into the combo boxes.
for bible in bibles: for bible in bibles:
@ -386,7 +392,7 @@ class BibleMediaItem(MediaManagerItem):
def reloadBibles(self): def reloadBibles(self):
log.debug(u'Reloading Bibles') log.debug(u'Reloading Bibles')
self.parent.manager.reload_bibles() self.plugin.manager.reload_bibles()
self.loadBibles() self.loadBibles()
def initialiseAdvancedBible(self, bible): def initialiseAdvancedBible(self, bible):
@ -400,7 +406,17 @@ class BibleMediaItem(MediaManagerItem):
The bible to initialise (unicode). The bible to initialise (unicode).
""" """
log.debug(u'initialiseAdvancedBible %s', bible) log.debug(u'initialiseAdvancedBible %s', bible)
book_data = self.parent.manager.get_books(bible) book_data = self.plugin.manager.get_books(bible)
secondbible = unicode(self.advancedSecondComboBox.currentText())
if secondbible != u'':
secondbook_data = self.plugin.manager.get_books(secondbible)
book_data_temp = []
for book in book_data:
for secondbook in secondbook_data:
if book['book_reference_id'] == \
secondbook['book_reference_id']:
book_data_temp.append(book)
book_data = book_data_temp
self.advancedBookComboBox.clear() self.advancedBookComboBox.clear()
first = True first = True
for book in book_data: for book in book_data:
@ -416,7 +432,7 @@ class BibleMediaItem(MediaManagerItem):
def initialiseChapterVerse(self, bible, book, chapter_count): def initialiseChapterVerse(self, bible, book, chapter_count):
log.debug(u'initialiseChapterVerse %s, %s', bible, book) log.debug(u'initialiseChapterVerse %s, %s', bible, book)
self.chapter_count = chapter_count self.chapter_count = chapter_count
verse_count = self.parent.manager.get_verse_count(bible, book, 1) verse_count = self.plugin.manager.get_verse_count(bible, book, 1)
if verse_count == 0: if verse_count == 0:
self.advancedSearchButton.setEnabled(False) self.advancedSearchButton.setEnabled(False)
critical_error_message_box( critical_error_message_box(
@ -445,18 +461,34 @@ class BibleMediaItem(MediaManagerItem):
books = [] books = []
# We have to do a 'Reference Search'. # We have to do a 'Reference Search'.
if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference: if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference:
bibles = self.parent.manager.get_bibles() bibles = self.plugin.manager.get_bibles()
bible = unicode(self.quickVersionComboBox.currentText()) bible = unicode(self.quickVersionComboBox.currentText())
if bible: if bible:
book_data = bibles[bible].get_books() book_data = bibles[bible].get_books()
secondbible = unicode(self.quickSecondComboBox.currentText())
if secondbible != u'':
secondbook_data = bibles[secondbible].get_books()
book_data_temp = []
for book in book_data:
for secondbook in secondbook_data:
if book.book_reference_id == \
secondbook.book_reference_id:
book_data_temp.append(book)
book_data = book_data_temp
books = [book.name + u' ' for book in book_data] books = [book.name + u' ' for book in book_data]
books.sort(cmp=locale.strcoll) books.sort(cmp=locale.strcoll)
add_widget_completer(books, self.quickSearchEdit) add_widget_completer(books, self.quickSearchEdit)
def onQuickVersionComboBox(self):
self.updateAutoCompleter()
def onQuickSecondComboBox(self):
self.updateAutoCompleter()
def onImportClick(self): def onImportClick(self):
if not hasattr(self, u'import_wizard'): if not hasattr(self, u'import_wizard'):
self.import_wizard = BibleImportForm(self, self.parent.manager, self.import_wizard = BibleImportForm(self, self.plugin.manager,
self.parent) self.plugin)
# If the import was not cancelled then reload. # If the import was not cancelled then reload.
if self.import_wizard.exec_(): if self.import_wizard.exec_():
self.reloadBibles() self.reloadBibles()
@ -501,6 +533,10 @@ class BibleMediaItem(MediaManagerItem):
self.initialiseAdvancedBible( self.initialiseAdvancedBible(
unicode(self.advancedVersionComboBox.currentText())) unicode(self.advancedVersionComboBox.currentText()))
def onAdvancedSecondComboBox(self):
self.initialiseAdvancedBible(
unicode(self.advancedVersionComboBox.currentText()))
def onAdvancedBookComboBox(self): def onAdvancedBookComboBox(self):
item = int(self.advancedBookComboBox.currentIndex()) item = int(self.advancedBookComboBox.currentIndex())
self.initialiseChapterVerse( self.initialiseChapterVerse(
@ -515,7 +551,7 @@ class BibleMediaItem(MediaManagerItem):
bible = unicode(self.advancedVersionComboBox.currentText()) bible = unicode(self.advancedVersionComboBox.currentText())
book = unicode(self.advancedBookComboBox.currentText()) book = unicode(self.advancedBookComboBox.currentText())
verse_from = int(self.advancedFromVerse.currentText()) verse_from = int(self.advancedFromVerse.currentText())
verse_count = self.parent.manager.get_verse_count(bible, book, verse_count = self.plugin.manager.get_verse_count(bible, book,
chapter_to) chapter_to)
self.adjustComboBox(verse_from, verse_count, self.adjustComboBox(verse_from, verse_count,
self.advancedToVerse, True) self.advancedToVerse, True)
@ -527,7 +563,7 @@ class BibleMediaItem(MediaManagerItem):
chapter_to = int(self.advancedToChapter.currentText()) chapter_to = int(self.advancedToChapter.currentText())
verse_from = int(self.advancedFromVerse.currentText()) verse_from = int(self.advancedFromVerse.currentText())
verse_to = int(self.advancedToVerse.currentText()) verse_to = int(self.advancedToVerse.currentText())
verse_count = self.parent.manager.get_verse_count(bible, book, verse_count = self.plugin.manager.get_verse_count(bible, book,
chapter_to) chapter_to)
if chapter_from == chapter_to and verse_from > verse_to: if chapter_from == chapter_to and verse_from > verse_to:
self.adjustComboBox(verse_from, verse_count, self.advancedToVerse) self.adjustComboBox(verse_from, verse_count, self.advancedToVerse)
@ -539,7 +575,7 @@ class BibleMediaItem(MediaManagerItem):
book = unicode(self.advancedBookComboBox.currentText()) book = unicode(self.advancedBookComboBox.currentText())
chapter_from = int(self.advancedFromChapter.currentText()) chapter_from = int(self.advancedFromChapter.currentText())
chapter_to = int(self.advancedToChapter.currentText()) chapter_to = int(self.advancedToChapter.currentText())
verse_count = self.parent.manager.get_verse_count(bible, book, verse_count = self.plugin.manager.get_verse_count(bible, book,
chapter_from) chapter_from)
self.adjustComboBox(1, verse_count, self.advancedFromVerse) self.adjustComboBox(1, verse_count, self.advancedFromVerse)
if chapter_from > chapter_to: if chapter_from > chapter_to:
@ -599,10 +635,10 @@ class BibleMediaItem(MediaManagerItem):
range_separator + chapter_to + verse_separator + verse_to range_separator + chapter_to + verse_separator + verse_to
versetext = u'%s %s' % (book, verse_range) versetext = u'%s %s' % (book, verse_range)
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
self.search_results = self.parent.manager.get_verses(bible, versetext) self.search_results = self.plugin.manager.get_verses(bible, versetext)
if second_bible: if second_bible:
self.second_search_results = self.parent.manager.get_verses( self.second_search_results = self.plugin.manager.get_verses(
second_bible, versetext) second_bible, versetext, bible)
if not self.advancedLockButton.isChecked(): if not self.advancedLockButton.isChecked():
self.listView.clear() self.listView.clear()
if self.listView.count() != 0: if self.listView.count() != 0:
@ -627,21 +663,44 @@ class BibleMediaItem(MediaManagerItem):
text = unicode(self.quickSearchEdit.text()) text = unicode(self.quickSearchEdit.text())
if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference: if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference:
# We are doing a 'Reference Search'. # We are doing a 'Reference Search'.
self.search_results = self.parent.manager.get_verses(bible, text) self.search_results = self.plugin.manager.get_verses(bible, text)
if second_bible and self.search_results: if second_bible and self.search_results:
self.second_search_results = self.parent.manager.get_verses( self.second_search_results = self.plugin.manager.get_verses(
second_bible, text) second_bible, text, bible)
else: else:
# We are doing a 'Text Search'. # We are doing a 'Text Search'.
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
bibles = self.parent.manager.get_bibles() bibles = self.plugin.manager.get_bibles()
self.search_results = self.parent.manager.verse_search(bible, self.search_results = self.plugin.manager.verse_search(bible,
second_bible, text) second_bible, text)
if second_bible and self.search_results: if second_bible and self.search_results:
text = [] text = []
new_search_results = []
count = 0
passage_not_found = False
for verse in self.search_results: for verse in self.search_results:
text.append((verse.book.name, verse.chapter, verse.verse, db_book = bibles[second_bible].get_book_by_book_ref_id(
verse.book.book_reference_id)
if not db_book:
log.debug(u'Passage "%s %d:%d" not found in Second '
u'Bible' % (verse.book.name, verse.chapter,
verse.verse)) verse.verse))
passage_not_found = True
count += 1
continue
new_search_results.append(verse)
text.append((verse.book.book_reference_id, verse.chapter,
verse.verse, verse.verse))
if passage_not_found:
QtGui.QMessageBox.information(self,
translate('BiblePlugin.MediaItem', 'Information'),
unicode(translate('BiblePlugin.MediaItem',
'The second Bibles does not contain all the verses '
'that are in the main Bible. Only verses found in both '
'Bibles will be shown. %d verses have not been '
'included in the results.')) % count,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
self.search_results = new_search_results
self.second_search_results = \ self.second_search_results = \
bibles[second_bible].get_verses(text) bibles[second_bible].get_verses(text)
if not self.quickLockButton.isChecked(): if not self.quickLockButton.isChecked():
@ -674,19 +733,19 @@ class BibleMediaItem(MediaManagerItem):
further action is saved for/in each row. further action is saved for/in each row.
""" """
verse_separator = get_reference_match(u'sep_v_display') verse_separator = get_reference_match(u'sep_v_display')
version = self.parent.manager.get_meta_data(bible, u'Version').value version = self.plugin.manager.get_meta_data(bible, u'Version').value
copyright = self.parent.manager.get_meta_data(bible, u'Copyright').value copyright = self.plugin.manager.get_meta_data(bible, u'Copyright').value
permissions = \ permissions = \
self.parent.manager.get_meta_data(bible, u'Permissions').value self.plugin.manager.get_meta_data(bible, u'Permissions').value
second_version = u'' second_version = u''
second_copyright = u'' second_copyright = u''
second_permissions = u'' second_permissions = u''
if second_bible: if second_bible:
second_version = self.parent.manager.get_meta_data( second_version = self.plugin.manager.get_meta_data(
second_bible, u'Version').value second_bible, u'Version').value
second_copyright = self.parent.manager.get_meta_data( second_copyright = self.plugin.manager.get_meta_data(
second_bible, u'Copyright').value second_bible, u'Copyright').value
second_permissions = self.parent.manager.get_meta_data( second_permissions = self.plugin.manager.get_meta_data(
second_bible, u'Permissions').value second_bible, u'Permissions').value
items = [] items = []
for count, verse in enumerate(search_results): for count, verse in enumerate(search_results):
@ -809,7 +868,8 @@ class BibleMediaItem(MediaManagerItem):
service_item.theme = None service_item.theme = None
else: else:
service_item.theme = self.settings.bible_theme service_item.theme = self.settings.bible_theme
[service_item.add_from_text(slide[:30], slide) for slide in raw_slides] for slide in raw_slides:
service_item.add_from_text(slide[:30], slide)
return True return True
def formatTitle(self, start_bitem, old_bitem): def formatTitle(self, start_bitem, old_bitem):
@ -879,7 +939,7 @@ class BibleMediaItem(MediaManagerItem):
# We are still in the same chapter, but a verse has been skipped. # We are still in the same chapter, but a verse has been skipped.
return True return True
elif old_chapter + 1 == chapter and (verse != 1 or elif old_chapter + 1 == chapter and (verse != 1 or
old_verse != self.parent.manager.get_verse_count( old_verse != self.plugin.manager.get_verse_count(
old_bible, old_book, old_chapter)): old_bible, old_book, old_chapter)):
# We are in the following chapter, but the last verse was not the # We are in the following chapter, but the last verse was not the
# last verse of the chapter or the current verse is not the # last verse of the chapter or the current verse is not the
@ -923,7 +983,7 @@ class BibleMediaItem(MediaManagerItem):
Search for some Bible verses (by reference). Search for some Bible verses (by reference).
""" """
bible = unicode(self.quickVersionComboBox.currentText()) bible = unicode(self.quickVersionComboBox.currentText())
search_results = self.parent.manager.get_verses(bible, string, False) search_results = self.plugin.manager.get_verses(bible, string, False)
results = [] results = []
if search_results: if search_results:
versetext = u' '.join([verse.text for verse in search_results]) versetext = u' '.join([verse.text for verse in search_results])
@ -933,6 +993,6 @@ class BibleMediaItem(MediaManagerItem):
def createItemFromId(self, item_id): def createItemFromId(self, item_id):
item = QtGui.QListWidgetItem() item = QtGui.QListWidgetItem()
bible = unicode(self.quickVersionComboBox.currentText()) bible = unicode(self.quickVersionComboBox.currentText())
search_results = self.parent.manager.get_verses(bible, item_id, False) search_results = self.plugin.manager.get_verses(bible, item_id, False)
items = self.buildDisplayResults(bible, u'', search_results) items = self.buildDisplayResults(bible, u'', search_results)
return items return items

View File

@ -30,7 +30,7 @@ import sqlite
from openlp.core.lib import Receiver from openlp.core.lib import Receiver
from openlp.core.ui.wizard import WizardStrings from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.bibles.lib.db import BibleDB from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -46,7 +46,7 @@ class OpenLP1Bible(BibleDB):
BibleDB.__init__(self, parent, **kwargs) BibleDB.__init__(self, parent, **kwargs)
self.filename = kwargs[u'filename'] self.filename = kwargs[u'filename']
def do_import(self): def do_import(self, bible_name=None):
""" """
Imports an openlp.org v1 bible. Imports an openlp.org v1 bible.
""" """
@ -57,6 +57,11 @@ class OpenLP1Bible(BibleDB):
cursor = connection.cursor() cursor = connection.cursor()
except: except:
return False return False
#Create the bible language
language_id = self.get_language(bible_name)
if not language_id:
log.exception(u'Importing books from "%s" failed' % self.filename)
return False
# Create all books. # Create all books.
cursor.execute(u'SELECT id, testament_id, name, abbreviation FROM book') cursor.execute(u'SELECT id, testament_id, name, abbreviation FROM book')
books = cursor.fetchall() books = cursor.fetchall()
@ -69,7 +74,15 @@ class OpenLP1Bible(BibleDB):
testament_id = int(book[1]) testament_id = int(book[1])
name = unicode(book[2], u'cp1252') name = unicode(book[2], u'cp1252')
abbreviation = unicode(book[3], u'cp1252') abbreviation = unicode(book[3], u'cp1252')
self.create_book(name, abbreviation, testament_id) book_ref_id = self.get_book_ref_id_by_name(name, len(books),
language_id)
if not book_ref_id:
log.exception(u'Importing books from "%s" '\
'failed' % self.filename)
return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.create_book(name, book_ref_id,
book_details[u'testament_id'])
# Update the progess bar. # Update the progess bar.
self.wizard.incrementProgressBar(WizardStrings.ImportingType % name) self.wizard.incrementProgressBar(WizardStrings.ImportingType % name)
# Import the verses for this book. # Import the verses for this book.
@ -83,7 +96,7 @@ class OpenLP1Bible(BibleDB):
chapter = int(verse[0]) chapter = int(verse[0])
verse_number = int(verse[1]) verse_number = int(verse[1])
text = unicode(verse[2], u'cp1252') text = unicode(verse[2], u'cp1252')
self.create_verse(book_id, chapter, verse_number, text) self.create_verse(db_book.id, chapter, verse_number, text)
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
self.session.commit() self.session.commit()
connection.close() connection.close()

View File

@ -29,7 +29,7 @@ import logging
from lxml import objectify from lxml import objectify
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate
from openlp.plugins.bibles.lib.db import BibleDB from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -46,7 +46,7 @@ class OpenSongBible(BibleDB):
BibleDB.__init__(self, parent, **kwargs) BibleDB.__init__(self, parent, **kwargs)
self.filename = kwargs['filename'] self.filename = kwargs['filename']
def do_import(self): def do_import(self, bible_name=None):
""" """
Loads a Bible from file. Loads a Bible from file.
""" """
@ -62,11 +62,23 @@ class OpenSongBible(BibleDB):
file = open(self.filename, u'r') file = open(self.filename, u'r')
opensong = objectify.parse(file) opensong = objectify.parse(file)
bible = opensong.getroot() bible = opensong.getroot()
language_id = self.get_language(bible_name)
if not language_id:
log.exception(u'Importing books from "%s" '\
'failed' % self.filename)
return False
for book in bible.b: for book in bible.b:
if self.stop_import_flag: if self.stop_import_flag:
break break
book_ref_id = self.get_book_ref_id_by_name(
unicode(book.attrib[u'n']), len(bible.b), language_id)
if not book_ref_id:
log.exception(u'Importing books from "%s" '\
'failed' % self.filename)
return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.create_book(unicode(book.attrib[u'n']), db_book = self.create_book(unicode(book.attrib[u'n']),
unicode(book.attrib[u'n'][:4])) book_ref_id, book_details[u'testament_id'])
for chapter in book.c: for chapter in book.c:
if self.stop_import_flag: if self.stop_import_flag:
break break

View File

@ -34,7 +34,7 @@ import re
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.db import BibleDB from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -86,7 +86,7 @@ class OSISBible(BibleDB):
if fbibles: if fbibles:
fbibles.close() fbibles.close()
def do_import(self): def do_import(self, bible_name=None):
""" """
Loads a Bible from file. Loads a Bible from file.
""" """
@ -96,7 +96,6 @@ class OSISBible(BibleDB):
osis = None osis = None
success = True success = True
last_chapter = 0 last_chapter = 0
testament = 1
match_count = 0 match_count = 0
self.wizard.incrementProgressBar(translate('BiblesPlugin.OsisImport', self.wizard.incrementProgressBar(translate('BiblesPlugin.OsisImport',
'Detecting encoding (this may take a few minutes)...')) 'Detecting encoding (this may take a few minutes)...'))
@ -109,6 +108,11 @@ class OSISBible(BibleDB):
finally: finally:
if detect_file: if detect_file:
detect_file.close() detect_file.close()
# Set meta language_id
language_id = self.get_language(bible_name)
if not language_id:
log.exception(u'Importing books from "%s" failed' % self.filename)
return False
try: try:
osis = codecs.open(self.filename, u'r', details['encoding']) osis = codecs.open(self.filename, u'r', details['encoding'])
repl = replacement repl = replacement
@ -123,13 +127,19 @@ class OSISBible(BibleDB):
verse = int(match.group(3)) verse = int(match.group(3))
verse_text = match.group(4) verse_text = match.group(4)
if not db_book or db_book.name != self.books[book][0]: if not db_book or db_book.name != self.books[book][0]:
log.debug(u'New book: "%s"', self.books[book][0]) log.debug(u'New book: "%s"' % self.books[book][0])
if book == u'Matt' or book == u'Jdt': book_ref_id = self.get_book_ref_id_by_name(unicode(
testament += 1 self.books[book][0]), 67, language_id)
if not book_ref_id:
log.exception(u'Importing books from "%s" '\
'failed' % self.filename)
return False
book_details = BiblesResourcesDB.get_book_by_id(
book_ref_id)
db_book = self.create_book( db_book = self.create_book(
unicode(self.books[book][0]), unicode(self.books[book][0]),
unicode(self.books[book][1]), book_ref_id,
testament) book_details[u'testament_id'])
if last_chapter == 0: if last_chapter == 0:
if book == u'Gen': if book == u'Gen':
self.wizard.progressBar.setMaximum(1188) self.wizard.progressBar.setMaximum(1188)

View File

@ -1,81 +0,0 @@
João Ferreira de Almeida Atualizada,AA
التفسير التطبيقى للكتاب المقدس,ALAB
Shqip,ALB
Amplified Bible,AMP
Amuzgo de Guerrero,AMU
American Standard Version,ASV
La Bible du Semeur,BDS
Български 1940,BG1940
Български,BULG
Chinanteco de Comaltepec,CCO
Contemporary English Version,CEV
Cakchiquel Occidental,CKW
Hrvatski,CRO
Castilian,CST
聖經和合本 (简体中文),CUVS
聖經和合本 (繁体中文),CUV
Darby Translation,DARBY
Dette er Biblen på dansk,DN1933
Det Norsk Bibelselskap 1930,DNB1930
English Standard Version,ESV
GODS WORD Translation,GW
Holman Christian Standard Bible,HCSB
Kreyòl ayisyen bib,HCV
Hiligaynon Bible,HLGN
Hoffnung für Alle,HOF
Het Boek,HTB
Icelandic Bible,ICELAND
Jacalteco Oriental,JAC
Károlyi-biblia,KAR
Kekchi,KEK
21st Century King James Version,KJ21
King James Version,KJV
La Biblia de las Américas,LBLA
Levande Bibeln,LB
La Parola è Vita,LM
La Nuova Diodati,LND
Louis Segond,LSG
Luther Bibel 1545,LUTH1545
Māori Bible,MAORI
Македонски Новиот Завет,MNT
The Message,MSG
Mam de Comitancillo Central,MVC
Mam de Todos Santos Cuchumatán,MVJ
New American Standard Bible,NASB
New Century Version,NCV
Náhuatl de Guerrero,NGU
New International Reader's Version,NIRV
New International Version 1984,NIV1984
New International Version 2010,NIV
New International Version - UK,NIVUK
New King James Version,NKJV
New Living Translation,NLT
Nádej pre kazdého,NPK
Nueva Versión Internacional,NVI
O Livro,OL
Quiché Centro Occidental,QUT
Reimer 2001,REIMER
Română Cornilescu,RMNN
Новый перевод на русский язык,RUSV
Reina-Valera Antigua,RVA
Reina-Valera 1960,RVR1960
Reina-Valera 1995,RVR1995
Slovo na cestu,SNC
Ang Salita ng Diyos,SND
Swahili New Testament,SNT
Svenska 1917,SV1917
Levande Bibeln,SVL
Создать страницу,SZ
Traducción en lenguaje actual,TLA
New Romanian Translation,TLCR
Todays New International Version 2005,TNIV
Textus Receptus Stephanus 1550,TR1550
Textus Receptus Scrivener 1894,TR1894
Українська Біблія. Переклад Івана Огієнка,UKR
Uspanteco,USP
Kinh Thánh tiếng Việt 1934,VIET
Worldwide English (New Testament),WE
Codex Vaticanus Westcott-Hort 1881,WHNU
Westminster Leningrad Codex,WLC
Wycliffe New Testament,WYC
Young's Literal Translation,YLT
1 João Ferreira de Almeida Atualizada AA
2 التفسير التطبيقى للكتاب المقدس ALAB
3 Shqip ALB
4 Amplified Bible AMP
5 Amuzgo de Guerrero AMU
6 American Standard Version ASV
7 La Bible du Semeur BDS
8 Български 1940 BG1940
9 Български BULG
10 Chinanteco de Comaltepec CCO
11 Contemporary English Version CEV
12 Cakchiquel Occidental CKW
13 Hrvatski CRO
14 Castilian CST
15 聖經和合本 (简体中文) CUVS
16 聖經和合本 (繁体中文) CUV
17 Darby Translation DARBY
18 Dette er Biblen på dansk DN1933
19 Det Norsk Bibelselskap 1930 DNB1930
20 English Standard Version ESV
21 GOD’S WORD Translation GW
22 Holman Christian Standard Bible HCSB
23 Kreyòl ayisyen bib HCV
24 Hiligaynon Bible HLGN
25 Hoffnung für Alle HOF
26 Het Boek HTB
27 Icelandic Bible ICELAND
28 Jacalteco – Oriental JAC
29 Károlyi-biblia KAR
30 Kekchi KEK
31 21st Century King James Version KJ21
32 King James Version KJV
33 La Biblia de las Américas LBLA
34 Levande Bibeln LB
35 La Parola è Vita LM
36 La Nuova Diodati LND
37 Louis Segond LSG
38 Luther Bibel 1545 LUTH1545
39 Māori Bible MAORI
40 Македонски Новиот Завет MNT
41 The Message MSG
42 Mam de Comitancillo Central MVC
43 Mam de Todos Santos Cuchumatán MVJ
44 New American Standard Bible NASB
45 New Century Version NCV
46 Náhuatl de Guerrero NGU
47 New International Reader's Version NIRV
48 New International Version 1984 NIV1984
49 New International Version 2010 NIV
50 New International Version - UK NIVUK
51 New King James Version NKJV
52 New Living Translation NLT
53 Nádej pre kazdého NPK
54 Nueva Versión Internacional NVI
55 O Livro OL
56 Quiché – Centro Occidental QUT
57 Reimer 2001 REIMER
58 Română Cornilescu RMNN
59 Новый перевод на русский язык RUSV
60 Reina-Valera Antigua RVA
61 Reina-Valera 1960 RVR1960
62 Reina-Valera 1995 RVR1995
63 Slovo na cestu SNC
64 Ang Salita ng Diyos SND
65 Swahili New Testament SNT
66 Svenska 1917 SV1917
67 Levande Bibeln SVL
68 Создать страницу SZ
69 Traducción en lenguaje actual TLA
70 New Romanian Translation TLCR
71 Today’s New International Version 2005 TNIV
72 Textus Receptus Stephanus 1550 TR1550
73 Textus Receptus Scrivener 1894 TR1894
74 Українська Біблія. Переклад Івана Огієнка UKR
75 Uspanteco USP
76 Kinh Thánh tiếng Việt 1934 VIET
77 Worldwide English (New Testament) WE
78 Codex Vaticanus Westcott-Hort 1881 WHNU
79 Westminster Leningrad Codex WLC
80 Wycliffe New Testament WYC
81 Young's Literal Translation YLT

View File

@ -1,39 +0,0 @@
عربي, ARA
Bible překlad 21. století, B21
Bible du Semeur, BDS
Българската Библия, BLG
Český ekumenický překlad, CEP
Hrvatski, CRO
Священное Писание, CRS
Version La Biblia al Dia, CST
中文和合本(简体), CUVS
Bibelen på hverdagsdansk, DK
Revidierte Elberfelder, ELB
Einheitsübersetzung, EU
Gute Nachricht Bibel, GNB
Hoffnung für alle, HFA
Hungarian, HUN
Het Boek, HTB
La Parola è Vita, ITA
IBS-fordítás (Új Károli), KAR
King James Version, KJV
Luther 1984, LUT
Septuaginta, LXX
Neue Genfer Übersetzung, NGU
New International Readers Version, NIRV
New International Version, NIV
Neues Leben, NL
En Levende Bok (NOR), NOR
Nádej pre kazdého, NPK
Noua traducere în limba românã, NTR
Nueva Versión Internacional, NVI
הברית הישנה, OT
Słowo Życia, POL
O Livro, PRT
Новый перевод на русский язык, RUS
Slovo na cestu, SNC
Schlachter 2000, SLT
En Levande Bok (SWE), SVL
Today's New International Version, TNIV
Türkçe, TR
Biblia Vulgata, VUL
1 عربي ARA
2 Bible – překlad 21. století B21
3 Bible du Semeur BDS
4 Българската Библия BLG
5 Český ekumenický překlad CEP
6 Hrvatski CRO
7 Священное Писание CRS
8 Version La Biblia al Dia CST
9 中文和合本(简体) CUVS
10 Bibelen på hverdagsdansk DK
11 Revidierte Elberfelder ELB
12 Einheitsübersetzung EU
13 Gute Nachricht Bibel GNB
14 Hoffnung für alle HFA
15 Hungarian HUN
16 Het Boek HTB
17 La Parola è Vita ITA
18 IBS-fordítás (Új Károli) KAR
19 King James Version KJV
20 Luther 1984 LUT
21 Septuaginta LXX
22 Neue Genfer Übersetzung NGU
23 New International Readers Version NIRV
24 New International Version NIV
25 Neues Leben NL
26 En Levende Bok (NOR) NOR
27 Nádej pre kazdého NPK
28 Noua traducere în limba românã NTR
29 Nueva Versión Internacional NVI
30 הברית הישנה OT
31 Słowo Życia POL
32 O Livro PRT
33 Новый перевод на русский язык RUS
34 Slovo na cestu SNC
35 Schlachter 2000 SLT
36 En Levande Bok (SWE) SVL
37 Today's New International Version TNIV
38 Türkçe TR
39 Biblia Vulgata VUL

View File

@ -1,27 +0,0 @@
New American Standard,nas
American Standard Version,asv
English Standard Version,esv
New King James Version,nkj
King James Version,kjv
Holman Christian Standard Bible,csb
Third Millennium Bible,tmb
New International Version,niv
New Living Translation,nlt
New Revised Standard,nrs
Revised Standard Version,rsv
Good News Translation,gnt
Douay-Rheims Bible,rhe
The Message,msg
The Complete Jewish Bible,cjb
New Century Version,ncv
GOD'S WORD Translation,gwd
Hebrew Names Version,hnv
World English Bible,web
The Bible in Basic English,bbe
Young's Literal Translation,ylt
Today's New International Version,tnv
New International Reader's Version,nrv
The Darby Translation,dby
The Webster Bible,wbt
The Latin Vulgate,vul
Weymouth New Testament,wnt
1 New American Standard nas
2 American Standard Version asv
3 English Standard Version esv
4 New King James Version nkj
5 King James Version kjv
6 Holman Christian Standard Bible csb
7 Third Millennium Bible tmb
8 New International Version niv
9 New Living Translation nlt
10 New Revised Standard nrs
11 Revised Standard Version rsv
12 Good News Translation gnt
13 Douay-Rheims Bible rhe
14 The Message msg
15 The Complete Jewish Bible cjb
16 New Century Version ncv
17 GOD'S WORD Translation gwd
18 Hebrew Names Version hnv
19 World English Bible web
20 The Bible in Basic English bbe
21 Young's Literal Translation ylt
22 Today's New International Version tnv
23 New International Reader's Version nrv
24 The Darby Translation dby
25 The Webster Bible wbt
26 The Latin Vulgate vul
27 Weymouth New Testament wnt

View File

@ -27,8 +27,6 @@
import logging import logging
from forms import EditCustomForm
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.plugins.custom.lib import CustomMediaItem, CustomTab from openlp.plugins.custom.lib import CustomMediaItem, CustomTab
@ -52,7 +50,6 @@ class CustomPlugin(Plugin):
CustomMediaItem, CustomTab) CustomMediaItem, CustomTab)
self.weight = -5 self.weight = -5
self.manager = Manager(u'custom', init_schema) self.manager = Manager(u'custom', init_schema)
self.edit_custom_form = EditCustomForm(self)
self.icon_path = u':/plugins/plugin_custom.png' self.icon_path = u':/plugins/plugin_custom.png'
self.icon = build_icon(self.icon_path) self.icon = build_icon(self.icon_path)

View File

@ -43,13 +43,13 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
Class documentation goes here. Class documentation goes here.
""" """
log.info(u'Custom Editor loaded') log.info(u'Custom Editor loaded')
def __init__(self, parent): def __init__(self, mediaitem, parent, manager):
""" """
Constructor Constructor
""" """
QtGui.QDialog.__init__(self) QtGui.QDialog.__init__(self, parent)
self.parent = parent self.manager = manager
self.manager = self.parent.manager self.mediaitem = mediaitem
self.setupUi(self) self.setupUi(self)
# Create other objects and forms. # Create other objects and forms.
self.editSlideForm = EditCustomSlideForm(self) self.editSlideForm = EditCustomSlideForm(self)
@ -115,9 +115,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
def accept(self): def accept(self):
log.debug(u'accept') log.debug(u'accept')
if self.saveCustom(): if self.saveCustom():
Receiver.send_message(u'custom_set_autoselect_item',
self.customSlide.title)
Receiver.send_message(u'custom_load_list')
QtGui.QDialog.accept(self) QtGui.QDialog.accept(self)
def saveCustom(self): def saveCustom(self):
@ -138,7 +135,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8') self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
self.customSlide.credits = unicode(self.creditEdit.text()) self.customSlide.credits = unicode(self.creditEdit.text())
self.customSlide.theme_name = unicode(self.themeComboBox.currentText()) self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
return self.manager.save_object(self.customSlide) success = self.manager.save_object(self.customSlide)
self.mediaitem.auto_select_id = self.customSlide.id
return success
def onUpButtonClicked(self): def onUpButtonClicked(self):
selectedRow = self.slideListView.currentRow() selectedRow = self.slideListView.currentRow()

View File

@ -35,6 +35,7 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
check_item_selected, translate check_item_selected, translate
from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings from openlp.core.lib.ui import UiStrings
from openlp.plugins.custom.forms import EditCustomForm
from openlp.plugins.custom.lib import CustomXMLParser from openlp.plugins.custom.lib import CustomXMLParser
from openlp.plugins.custom.lib.db import CustomSlide from openlp.plugins.custom.lib.db import CustomSlide
@ -56,14 +57,16 @@ class CustomMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon): def __init__(self, parent, plugin, icon):
self.IconPath = u'custom/custom' self.IconPath = u'custom/custom'
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
self.edit_custom_form = EditCustomForm(self, self.plugin.formparent,
self.plugin.manager)
self.singleServiceItem = False self.singleServiceItem = False
self.quickPreviewAllowed = True self.quickPreviewAllowed = True
self.hasSearch = True self.hasSearch = True
# Holds information about whether the edit is remotly triggered and # Holds information about whether the edit is remotly triggered and
# which Custom is required. # which Custom is required.
self.remoteCustom = -1 self.remoteCustom = -1
self.manager = parent.manager self.manager = plugin.manager
def addEndHeaderBar(self): def addEndHeaderBar(self):
self.addToolbarSeparator() self.addToolbarSeparator()
@ -106,7 +109,7 @@ class CustomMediaItem(MediaManagerItem):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'custom_edit_clear'), self.onRemoteEditClear) QtCore.SIGNAL(u'custom_edit_clear'), self.onRemoteEditClear)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'custom_load_list'), self.initialise) QtCore.SIGNAL(u'custom_load_list'), self.loadList)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick) QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick)
@ -126,16 +129,10 @@ class CustomMediaItem(MediaManagerItem):
self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value( self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value(
u'%s/last search type' % self.settingsSection, u'%s/last search type' % self.settingsSection,
QtCore.QVariant(CustomSearch.Titles)).toInt()[0]) QtCore.QVariant(CustomSearch.Titles)).toInt()[0])
# Called to redisplay the custom list screen edith from a search
# or from the exit of the Custom edit dialog. If remote editing is
# active trigger it and clean up so it will not update again.
if self.remoteTriggered == u'L':
self.onAddClick()
if self.remoteTriggered == u'P':
self.onPreviewClick()
self.onRemoteEditClear()
def loadList(self, custom_slides): def loadList(self, custom_slides):
# Sort out what custom we want to select after loading the list.
self.save_auto_select_id()
self.listView.clear() self.listView.clear()
# Sort the customs by its title considering language specific # Sort the customs by its title considering language specific
# characters. lower() is needed for windows! # characters. lower() is needed for windows!
@ -146,33 +143,45 @@ class CustomMediaItem(MediaManagerItem):
custom_name.setData( custom_name.setData(
QtCore.Qt.UserRole, QtCore.QVariant(custom_slide.id)) QtCore.Qt.UserRole, QtCore.QVariant(custom_slide.id))
self.listView.addItem(custom_name) self.listView.addItem(custom_name)
# Auto-select the item if name has been set # Auto-select the custom.
if custom_slide.title == self.autoSelectItem: if custom_slide.id == self.auto_select_id:
self.listView.setCurrentItem(custom_name) self.listView.setCurrentItem(custom_name)
self.auto_select_id = -1
# Called to redisplay the custom list screen edith from a search
# or from the exit of the Custom edit dialog. If remote editing is
# active trigger it and clean up so it will not update again.
if self.remoteTriggered == u'L':
self.onAddClick()
if self.remoteTriggered == u'P':
self.onPreviewClick()
self.onRemoteEditClear()
def onNewClick(self): def onNewClick(self):
self.parent.edit_custom_form.loadCustom(0) self.edit_custom_form.loadCustom(0)
self.parent.edit_custom_form.exec_() self.edit_custom_form.exec_()
self.initialise() self.onClearTextButtonClick()
self.onSelectionChange()
def onRemoteEditClear(self): def onRemoteEditClear(self):
self.remoteTriggered = None self.remoteTriggered = None
self.remoteCustom = -1 self.remoteCustom = -1
def onRemoteEdit(self, customid): def onRemoteEdit(self, message):
""" """
Called by ServiceManager or SlideController by event passing Called by ServiceManager or SlideController by event passing
the Song Id in the payload along with an indicator to say which the custom Id in the payload along with an indicator to say which
type of display is required. type of display is required.
""" """
fields = customid.split(u':') remote_type, custom_id = message.split(u':')
valid = self.manager.get_object(CustomSlide, fields[1]) custom_id = int(custom_id)
valid = self.manager.get_object(CustomSlide, custom_id)
if valid: if valid:
self.remoteCustom = fields[1] self.remoteCustom = custom_id
self.remoteTriggered = fields[0] self.remoteTriggered = remote_type
self.parent.edit_custom_form.loadCustom(fields[1], self.edit_custom_form.loadCustom(custom_id, (remote_type == u'P'))
(fields[0] == u'P')) self.edit_custom_form.exec_()
self.parent.edit_custom_form.exec_() self.auto_select_id = -1
self.onSearchTextButtonClick()
def onEditClick(self): def onEditClick(self):
""" """
@ -181,9 +190,10 @@ class CustomMediaItem(MediaManagerItem):
if check_item_selected(self.listView, UiStrings().SelectEdit): if check_item_selected(self.listView, UiStrings().SelectEdit):
item = self.listView.currentItem() item = self.listView.currentItem()
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.parent.edit_custom_form.loadCustom(item_id, False) self.edit_custom_form.loadCustom(item_id, False)
self.parent.edit_custom_form.exec_() self.edit_custom_form.exec_()
self.initialise() self.auto_select_id = -1
self.onSearchTextButtonClick()
def onDeleteClick(self): def onDeleteClick(self):
""" """
@ -195,7 +205,7 @@ class CustomMediaItem(MediaManagerItem):
id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0] id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0]
for item in self.listView.selectedIndexes()] for item in self.listView.selectedIndexes()]
for id in id_list: for id in id_list:
self.parent.manager.delete_object(CustomSlide, id) self.plugin.manager.delete_object(CustomSlide, id)
for row in row_list: for row in row_list:
self.listView.takeItem(row) self.listView.takeItem(row)
@ -203,7 +213,6 @@ class CustomMediaItem(MediaManagerItem):
self.searchTextEdit.setFocus() self.searchTextEdit.setFocus()
def generateSlideData(self, service_item, item=None, xmlVersion=False): def generateSlideData(self, service_item, item=None, xmlVersion=False):
raw_slides = []
raw_footer = [] raw_footer = []
slide = None slide = None
theme = None theme = None
@ -212,7 +221,7 @@ class CustomMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsPreview) service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop) service_item.add_capability(ItemCapabilities.AllowsLoop)
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit) service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
customSlide = self.parent.manager.get_object(CustomSlide, item_id) customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
title = customSlide.title title = customSlide.title
credit = customSlide.credits credit = customSlide.credits
service_item.edit_id = item_id service_item.edit_id = item_id
@ -221,8 +230,7 @@ class CustomMediaItem(MediaManagerItem):
service_item.theme = theme service_item.theme = theme
customXML = CustomXMLParser(customSlide.text) customXML = CustomXMLParser(customSlide.text)
verseList = customXML.get_verses() verseList = customXML.get_verses()
for verse in verseList: raw_slides = [verse[1] for verse in verseList]
raw_slides.append(verse[1])
service_item.title = title service_item.title = title
for slide in raw_slides: for slide in raw_slides:
service_item.add_from_text(slide[:30], slide) service_item.add_from_text(slide[:30], slide)
@ -245,13 +253,13 @@ class CustomMediaItem(MediaManagerItem):
search_type = self.searchTextEdit.currentSearchType() search_type = self.searchTextEdit.currentSearchType()
if search_type == CustomSearch.Titles: if search_type == CustomSearch.Titles:
log.debug(u'Titles Search') log.debug(u'Titles Search')
search_results = self.parent.manager.get_all_objects(CustomSlide, search_results = self.plugin.manager.get_all_objects(CustomSlide,
CustomSlide.title.like(u'%' + self.whitespace.sub(u' ', CustomSlide.title.like(u'%' + self.whitespace.sub(u' ',
search_keywords) + u'%'), order_by_ref=CustomSlide.title) search_keywords) + u'%'), order_by_ref=CustomSlide.title)
self.loadList(search_results) self.loadList(search_results)
elif search_type == CustomSearch.Themes: elif search_type == CustomSearch.Themes:
log.debug(u'Theme Search') log.debug(u'Theme Search')
search_results = self.parent.manager.get_all_objects(CustomSlide, search_results = self.plugin.manager.get_all_objects(CustomSlide,
CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ', CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ',
search_keywords) + u'%'), order_by_ref=CustomSlide.title) search_keywords) + u'%'), order_by_ref=CustomSlide.title)
self.loadList(search_results) self.loadList(search_results)
@ -260,7 +268,7 @@ class CustomMediaItem(MediaManagerItem):
def onSearchTextEditChanged(self, text): def onSearchTextEditChanged(self, text):
""" """
If search as type enabled invoke the search on each key press. If search as type enabled invoke the search on each key press.
If the Title is being searched do not start till 2 characters If the Title is being searched do not start until 2 characters
have been entered. have been entered.
""" """
search_length = 2 search_length = 2
@ -283,8 +291,5 @@ class CustomMediaItem(MediaManagerItem):
func.lower(CustomSlide.text).like(u'%' + func.lower(CustomSlide.text).like(u'%' +
string.lower() + u'%')), string.lower() + u'%')),
order_by_ref=CustomSlide.title) order_by_ref=CustomSlide.title)
results = [] return [[custom.id, custom.title] for custom in search_results]
for custom in search_results:
results.append([custom.id, custom.title])
return results

View File

@ -47,7 +47,7 @@ class ImageMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon): def __init__(self, parent, plugin, icon):
self.IconPath = u'images/image' self.IconPath = u'images/image'
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
self.quickPreviewAllowed = True self.quickPreviewAllowed = True
self.hasSearch = True self.hasSearch = True
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
@ -112,14 +112,14 @@ class ImageMediaItem(MediaManagerItem):
def loadList(self, list, initialLoad=False): def loadList(self, list, initialLoad=False):
if not initialLoad: if not initialLoad:
self.parent.formparent.displayProgressBar(len(list)) self.plugin.formparent.displayProgressBar(len(list))
# Sort the themes by its filename considering language specific # Sort the themes by its filename considering language specific
# characters. lower() is needed for windows! # characters. lower() is needed for windows!
list.sort(cmp=locale.strcoll, list.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower()) key=lambda filename: os.path.split(unicode(filename))[1].lower())
for imageFile in list: for imageFile in list:
if not initialLoad: if not initialLoad:
self.parent.formparent.incrementProgressBar() self.plugin.formparent.incrementProgressBar()
filename = os.path.split(unicode(imageFile))[1] filename = os.path.split(unicode(imageFile))[1]
thumb = os.path.join(self.servicePath, filename) thumb = os.path.join(self.servicePath, filename)
if os.path.exists(thumb): if os.path.exists(thumb):
@ -134,7 +134,7 @@ class ImageMediaItem(MediaManagerItem):
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
self.listView.addItem(item_name) self.listView.addItem(item_name)
if not initialLoad: if not initialLoad:
self.parent.formparent.finishedProgressBar() self.plugin.formparent.finishedProgressBar()
def generateSlideData(self, service_item, item=None, xmlVersion=False): def generateSlideData(self, service_item, item=None, xmlVersion=False):
if item: if item:
@ -188,7 +188,7 @@ class ImageMediaItem(MediaManagerItem):
Called to reset the Live backgound with the image selected, Called to reset the Live backgound with the image selected,
""" """
self.resetAction.setVisible(False) self.resetAction.setVisible(False)
self.parent.liveController.display.resetImage() self.plugin.liveController.display.resetImage()
def liveThemeChanged(self): def liveThemeChanged(self):
""" """
@ -208,7 +208,7 @@ class ImageMediaItem(MediaManagerItem):
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): if os.path.exists(filename):
(path, name) = os.path.split(filename) (path, name) = os.path.split(filename)
self.parent.liveController.display.directImage(name, filename) self.plugin.liveController.display.directImage(name, filename)
self.resetAction.setVisible(True) self.resetAction.setVisible(True)
else: else:
critical_error_message_box(UiStrings().LiveBGError, critical_error_message_box(UiStrings().LiveBGError,

View File

@ -50,7 +50,7 @@ class MediaMediaItem(MediaManagerItem):
self.background = False self.background = False
self.PreviewFunction = QtGui.QPixmap( self.PreviewFunction = QtGui.QPixmap(
u':/media/media_video.png').toImage() u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
self.singleServiceItem = False self.singleServiceItem = False
self.hasSearch = True self.hasSearch = True
self.mediaObject = None self.mediaObject = None
@ -65,8 +65,8 @@ class MediaMediaItem(MediaManagerItem):
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem', self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
'Videos (%s);;Audio (%s);;%s (*)')) % ( 'Videos (%s);;Audio (%s);;%s (*)')) % (
u' '.join(self.parent.video_extensions_list), u' '.join(self.plugin.video_extensions_list),
u' '.join(self.parent.audio_extensions_list), UiStrings().AllFiles) u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
self.replaceAction.setText(UiStrings().ReplaceBG) self.replaceAction.setText(UiStrings().ReplaceBG)
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG) self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
self.resetAction.setText(UiStrings().ResetBG) self.resetAction.setText(UiStrings().ResetBG)
@ -95,7 +95,7 @@ class MediaMediaItem(MediaManagerItem):
Called to reset the Live backgound with the media selected, Called to reset the Live backgound with the media selected,
""" """
self.resetAction.setVisible(False) self.resetAction.setVisible(False)
self.parent.liveController.display.resetVideo() self.plugin.liveController.display.resetVideo()
def videobackgroundReplaced(self): def videobackgroundReplaced(self):
""" """
@ -114,7 +114,7 @@ class MediaMediaItem(MediaManagerItem):
filename = unicode(item.data(QtCore.Qt.UserRole).toString()) filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): if os.path.exists(filename):
(path, name) = os.path.split(filename) (path, name) = os.path.split(filename)
self.parent.liveController.display.video(filename, 0, True) self.plugin.liveController.display.video(filename, 0, True)
self.resetAction.setVisible(True) self.resetAction.setVisible(True)
else: else:
critical_error_message_box(UiStrings().LiveBGError, critical_error_message_box(UiStrings().LiveBGError,

View File

@ -125,7 +125,7 @@ class ImpressController(PresentationController):
try: try:
uno_instance = get_uno_instance(resolver) uno_instance = get_uno_instance(resolver)
except: except:
log.exception(u'Unable to find running instance ') log.warn(u'Unable to find running instance ')
self.start_process() self.start_process()
loop += 1 loop += 1
try: try:
@ -136,7 +136,7 @@ class ImpressController(PresentationController):
"com.sun.star.frame.Desktop", uno_instance) "com.sun.star.frame.Desktop", uno_instance)
return desktop return desktop
except: except:
log.exception(u'Failed to get UNO desktop') log.warn(u'Failed to get UNO desktop')
return None return None
def get_com_desktop(self): def get_com_desktop(self):
@ -151,7 +151,7 @@ class ImpressController(PresentationController):
try: try:
desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop') desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop')
except AttributeError: except AttributeError:
log.exception(u'Failure to find desktop - Impress may have closed') log.warn(u'Failure to find desktop - Impress may have closed')
return desktop if desktop else None return desktop if desktop else None
def get_com_servicemanager(self): def get_com_servicemanager(self):
@ -162,7 +162,7 @@ class ImpressController(PresentationController):
try: try:
return Dispatch(u'com.sun.star.ServiceManager') return Dispatch(u'com.sun.star.ServiceManager')
except pywintypes.com_error: except pywintypes.com_error:
log.exception(u'Failed to get COM service manager. ' log.warn(u'Failed to get COM service manager. '
u'Impress Controller has been disabled') u'Impress Controller has been disabled')
return None return None
@ -180,7 +180,7 @@ class ImpressController(PresentationController):
else: else:
desktop = self.get_com_desktop() desktop = self.get_com_desktop()
except: except:
log.exception(u'Failed to find an OpenOffice desktop to terminate') log.warn(u'Failed to find an OpenOffice desktop to terminate')
if not desktop: if not desktop:
return return
docs = desktop.getComponents() docs = desktop.getComponents()
@ -191,7 +191,7 @@ class ImpressController(PresentationController):
desktop.terminate() desktop.terminate()
log.debug(u'OpenOffice killed') log.debug(u'OpenOffice killed')
except: except:
log.exception(u'Failed to terminate OpenOffice') log.warn(u'Failed to terminate OpenOffice')
class ImpressDocument(PresentationDocument): class ImpressDocument(PresentationDocument):
@ -244,7 +244,7 @@ class ImpressDocument(PresentationDocument):
self.document = desktop.loadComponentFromURL(url, u'_blank', self.document = desktop.loadComponentFromURL(url, u'_blank',
0, properties) 0, properties)
except: except:
log.exception(u'Failed to load presentation %s' % url) log.warn(u'Failed to load presentation %s' % url)
return False return False
if os.name == u'nt': if os.name == u'nt':
# As we can't start minimized the Impress window gets in the way. # As we can't start minimized the Impress window gets in the way.
@ -323,7 +323,7 @@ class ImpressDocument(PresentationDocument):
self.presentation = None self.presentation = None
self.document.dispose() self.document.dispose()
except: except:
log.exception("Closing presentation failed") log.warn("Closing presentation failed")
self.document = None self.document = None
self.controller.remove_doc(self) self.controller.remove_doc(self)
@ -341,7 +341,7 @@ class ImpressDocument(PresentationDocument):
log.debug("getPresentation failed to find a presentation") log.debug("getPresentation failed to find a presentation")
return False return False
except: except:
log.exception("getPresentation failed to find a presentation") log.warn("getPresentation failed to find a presentation")
return False return False
return True return True

View File

@ -46,14 +46,14 @@ class PresentationMediaItem(MediaManagerItem):
""" """
log.info(u'Presentations Media Item loaded') log.info(u'Presentations Media Item loaded')
def __init__(self, parent, icon, title, controllers): def __init__(self, parent, plugin, icon, controllers):
""" """
Constructor. Setup defaults Constructor. Setup defaults
""" """
self.controllers = controllers self.controllers = controllers
self.IconPath = u'presentations/presentation' self.IconPath = u'presentations/presentation'
self.Automatic = u'' self.Automatic = u''
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
self.message_listener = MessageListener(self) self.message_listener = MessageListener(self)
self.hasSearch = True self.hasSearch = True
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
@ -82,7 +82,7 @@ class PresentationMediaItem(MediaManagerItem):
for type in types: for type in types:
if fileType.find(type) == -1: if fileType.find(type) == -1:
fileType += u'*.%s ' % type fileType += u'*.%s ' % type
self.parent.serviceManager.supportedSuffixes(type) self.plugin.serviceManager.supportedSuffixes(type)
self.onNewFileMasks = unicode(translate('PresentationPlugin.MediaItem', self.onNewFileMasks = unicode(translate('PresentationPlugin.MediaItem',
'Presentations (%s)')) % fileType 'Presentations (%s)')) % fileType
@ -161,14 +161,14 @@ class PresentationMediaItem(MediaManagerItem):
titles = [os.path.split(file)[1] for file in currlist] titles = [os.path.split(file)[1] for file in currlist]
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
if not initialLoad: if not initialLoad:
self.parent.formparent.displayProgressBar(len(files)) self.plugin.formparent.displayProgressBar(len(files))
# Sort the themes by its filename considering language specific # Sort the themes by its filename considering language specific
# characters. lower() is needed for windows! # characters. lower() is needed for windows!
files.sort(cmp=locale.strcoll, files.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower()) key=lambda filename: os.path.split(unicode(filename))[1].lower())
for file in files: for file in files:
if not initialLoad: if not initialLoad:
self.parent.formparent.incrementProgressBar() self.plugin.formparent.incrementProgressBar()
if currlist.count(file) > 0: if currlist.count(file) > 0:
continue continue
filename = os.path.split(unicode(file))[1] filename = os.path.split(unicode(file))[1]
@ -208,7 +208,7 @@ class PresentationMediaItem(MediaManagerItem):
self.listView.addItem(item_name) self.listView.addItem(item_name)
Receiver.send_message(u'cursor_normal') Receiver.send_message(u'cursor_normal')
if not initialLoad: if not initialLoad:
self.parent.formparent.finishedProgressBar() self.plugin.formparent.finishedProgressBar()
def onDeleteClick(self): def onDeleteClick(self):
""" """

View File

@ -77,7 +77,7 @@ class PresentationPlugin(Plugin):
try: try:
self.controllers[controller].start_process() self.controllers[controller].start_process()
except: except:
log.exception(u'Failed to start controller process') log.warn(u'Failed to start controller process')
self.controllers[controller].available = False self.controllers[controller].available = False
self.mediaItem.buildFileMaskString() self.mediaItem.buildFileMaskString()
@ -99,7 +99,7 @@ class PresentationPlugin(Plugin):
Create the Media Manager List Create the Media Manager List
""" """
return PresentationMediaItem( return PresentationMediaItem(
self, self.icon, self.name, self.controllers) self.mediadock.media_dock, self, self.icon, self.controllers)
def registerControllers(self, controller): def registerControllers(self, controller):
""" """
@ -128,7 +128,7 @@ class PresentationPlugin(Plugin):
try: try:
__import__(modulename, globals(), locals(), []) __import__(modulename, globals(), locals(), [])
except ImportError: except ImportError:
log.exception(u'Failed to import %s on path %s', log.warn(u'Failed to import %s on path %s',
modulename, path) modulename, path)
controller_classes = PresentationController.__subclasses__() controller_classes = PresentationController.__subclasses__()
for controller_class in controller_classes: for controller_class in controller_classes:

View File

@ -27,91 +27,109 @@
--> -->
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>OpenLP 2.0 Remote</title> <title>${app_title}</title>
<link rel="stylesheet" href="/files/jquery.mobile.css" /> <link rel="stylesheet" href="/files/jquery.mobile.css" />
<link rel="stylesheet" href="/files/openlp.css" /> <link rel="stylesheet" href="/files/openlp.css" />
<script type="text/javascript" src="/files/jquery.js"></script> <script type="text/javascript" src="/files/jquery.js"></script>
<script type="text/javascript" src="/files/openlp.js"></script> <script type="text/javascript" src="/files/openlp.js"></script>
<script type="text/javascript" src="/files/jquery.mobile.js"></script> <script type="text/javascript" src="/files/jquery.mobile.js"></script>
<script type="text/javascript">
translationStrings = {
"go_live": "${go_live}",
"add_to_service": "${add_to_service}",
"no_results": "${no_results}",
"back": "${back}"
}
</script>
</head> </head>
<body> <body>
<div data-role="page" id="home"> <div data-role="page" id="home">
<div data-role="header"> <div data-role="header">
<h1>OpenLP 2.0 Remote</h1> <h1>${app_title}</h1>
</div> </div>
<div data-role="content"> <div data-role="content">
<div data-role="controlgroup"> <div data-role="controlgroup">
<a href="#service-manager" data-role="button" data-icon="arrow-r" data-iconpos="right">Service Manager</a> <a href="#service-manager" data-role="button" data-icon="arrow-r" data-iconpos="right">${service_manager}</a>
<a href="#slide-controller" data-role="button" data-icon="arrow-r" data-iconpos="right">Slide Controller</a> <a href="#slide-controller" data-role="button" data-icon="arrow-r" data-iconpos="right">${slide_controller}</a>
<a href="#alerts" data-role="button" data-icon="arrow-r" data-iconpos="right">Alerts</a> <a href="#alerts" data-role="button" data-icon="arrow-r" data-iconpos="right">${alerts}</a>
<a href="#search" data-role="button" data-icon="arrow-r" data-iconpos="right">Search</a> <a href="#search" data-role="button" data-icon="arrow-r" data-iconpos="right">${search}</a>
</div> </div>
</div> </div>
</div> </div>
<div data-role="page" id="service-manager"> <div data-role="page" id="service-manager">
<div data-role="header"> <div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a> <a href="#" data-rel="back" data-icon="arrow-l">${back}</a>
<h1>Service Manager</h1> <h1>${service_manager}</h1>
<a href="#" id="service-refresh" data-role="button" data-icon="refresh">Refresh</a> <a href="#" id="service-refresh" data-role="button" data-icon="refresh">${refresh}</a>
</div> </div>
<div data-role="content"> <div data-role="content">
<ul data-role="listview" data-inset="true"> <ul data-role="listview" data-inset="true">
</ul> </ul>
</div> </div>
<div data-role="footer" data-theme="b" class="ui-bar"> <div data-role="footer" data-theme="b" class="ui-bar">
<a href="#" id="service-blank" data-role="button" data-icon="blank">Blank</a> <a href="#" id="service-blank" data-role="button" data-icon="blank">${blank}</a>
<a href="#" id="service-unblank" data-role="button" data-icon="unblank">Show</a> <a href="#" id="service-unblank" data-role="button" data-icon="unblank">${show}</a>
<a href="#" id="service-previous" data-role="button" data-icon="arrow-l">Prev</a> <a href="#" id="service-previous" data-role="button" data-icon="arrow-l">${prev}</a>
<a href="#" id="service-next" data-role="button" data-icon="arrow-r" data-iconpos="right">Next</a> <a href="#" id="service-next" data-role="button" data-icon="arrow-r" data-iconpos="right">${next}</a>
</div> </div>
</div> </div>
<div data-role="page" id="slide-controller"> <div data-role="page" id="slide-controller">
<div data-role="header"> <div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a> <a href="#" data-rel="back" data-icon="arrow-l">${back}</a>
<h1>Slide Controller</h1> <h1>${slide_controller}</h1>
<a href="#" id="controller-refresh" data-role="button" data-icon="refresh">Refresh</a> <a href="#" id="controller-refresh" data-role="button" data-icon="refresh">${refresh}</a>
</div> </div>
<div data-role="content"> <div data-role="content">
<ul data-role="listview" data-inset="true"> <ul data-role="listview" data-inset="true">
</ul> </ul>
</div> </div>
<div data-role="footer" data-theme="b" class="ui-bar"> <div data-role="footer" data-theme="b" class="ui-bar">
<a href="#" id="controller-blank" data-role="button" data-icon="blank">Blank</a> <a href="#" id="controller-blank" data-role="button" data-icon="blank">${blank}</a>
<a href="#" id="controller-unblank" data-role="button" data-icon="unblank">Show</a> <a href="#" id="controller-unblank" data-role="button" data-icon="unblank">${show}</a>
<a href="#" id="controller-previous" data-role="button" data-icon="arrow-l">Prev</a> <a href="#" id="controller-previous" data-role="button" data-icon="arrow-l">${prev}</a>
<a href="#" id="controller-next" data-role="button" data-icon="arrow-r" data-iconpos="right">Next</a> <a href="#" id="controller-next" data-role="button" data-icon="arrow-r" data-iconpos="right">${next}</a>
</div> </div>
</div> </div>
<div data-role="page" id="alerts"> <div data-role="page" id="alerts">
<div data-role="header"> <div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a> <a href="#" data-rel="back" data-icon="arrow-l">${back}</a>
<h1>Alerts</h1> <h1>${alerts}</h1>
</div> </div>
<div data-role="content"> <div data-role="content">
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="alert-text">Text:</label> <label for="alert-text">${text}:</label>
<input type="text" name="alert-text" id="alert-text" value="" /> <input type="text" name="alert-text" id="alert-text" value="" />
</div> </div>
<a href="#" id="alert-submit" data-role="button">Show Alert</a> <a href="#" id="alert-submit" data-role="button">${show_alert}</a>
</div> </div>
</div> </div>
<div data-role="page" id="search"> <div data-role="page" id="search">
<div data-role="header"> <div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a> <a href="#" data-rel="back" data-icon="arrow-l">${back}</a>
<h1>Search</h1> <h1>${search}</h1>
</div> </div>
<div data-role="content"> <div data-role="content">
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="search-plugin">Search:</label> <label for="search-plugin">${search}:</label>
<select name="search-plugin" id="search-plugin" data-native-menu="false"></select> <select name="search-plugin" id="search-plugin" data-native-menu="false"></select>
</div> </div>
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="search-text">Text:</label> <label for="search-text">${text}:</label>
<input type="search" name="search-text" id="search-text" value="" /> <input type="search" name="search-text" id="search-text" value="" />
</div> </div>
<a href="#" id="search-submit" data-role="button">Search</a> <a href="#" id="search-submit" data-role="button">${search}</a>
<ul data-role="listview" data-inset="true"> <ul data-role="listview" data-inset="true">
</div> </div>
</div> </div>
<div data-role="page" id="options">
<div data-role="header" data-position="inline" data-theme="b">
<h1>${options}</h1>
</div>
<div data-role="content">
<input type="hidden" id="selected-item" value="" />
<a href="#" id="go-live" data-role="button">${go_live}</a>
<a href="#" id="add-to-service" data-role="button">${add_to_service}</a>
</div>
</div>
</body> </body>
</html> </html>

0
openlp/plugins/remotes/html/json2.js Executable file → Normal file
View File

View File

@ -47,7 +47,7 @@ window.OpenLP = {
var select = $("#search-plugin"); var select = $("#search-plugin");
select.html(""); select.html("");
$.each(data.results.items, function (idx, value) { $.each(data.results.items, function (idx, value) {
select.append("<option value='" + value + "'>" + value + "</option>"); select.append("<option value='" + value[0] + "'>" + value[1] + "</option>");
}); });
select.selectmenu("refresh"); select.selectmenu("refresh");
} }
@ -215,16 +215,15 @@ window.OpenLP = {
var ul = $("#search > div[data-role=content] > ul[data-role=listview]"); var ul = $("#search > div[data-role=content] > ul[data-role=listview]");
ul.html(""); ul.html("");
if (data.results.items.length == 0) { if (data.results.items.length == 0) {
var li = $("<li data-icon=\"false\">").text('No results'); var li = $("<li data-icon=\"false\">").text(translationStrings["no_results"]);
ul.append(li); ul.append(li);
} }
else { else {
$.each(data.results.items, function (idx, value) { $.each(data.results.items, function (idx, value) {
var item = $("<li>").text(value[1]); ul.append($("<li>").append($("<a>").attr("href", "#options")
var golive = $("<a href=\"#\">Go Live</a>").attr("value", value[0]).click(OpenLP.goLive); .attr("data-rel", "dialog").attr("data-transition", "pop")
var additem = $("<a href=\"#\">Add To Service</a>").attr("value", value[0]).click(OpenLP.addToService); .attr("value", value[0]).click(OpenLP.showOptions)
item.append($("<ul>").append($("<li>").append(golive)).append($("<li>").append(additem))); .text(value[1])));
ul.append(item);
}); });
} }
ul.listview("refresh"); ul.listview("refresh");
@ -232,19 +231,23 @@ window.OpenLP = {
); );
return false; return false;
}, },
showOptions: function (event) {
var element = OpenLP.getElement(event);
console.log(element);
$("#selected-item").val(element.attr("value"));
},
goLive: function (event) { goLive: function (event) {
var item = OpenLP.getElement(event); var id = $("#selected-item").val();
var id = item.attr("value");
var text = JSON.stringify({"request": {"id": id}}); var text = JSON.stringify({"request": {"id": id}});
$.getJSON( $.getJSON(
"/api/" + $("#search-plugin").val() + "/live", "/api/" + $("#search-plugin").val() + "/live",
{"data": text}) {"data": text}
$.mobile.changePage("slide-controller"); );
$.mobile.changePage("#slide-controller");
return false; return false;
}, },
addToService: function (event) { addToService: function (event) {
var item = OpenLP.getElement(event); var id = $("#selected-item").val();
var id = item.attr("value");
var text = JSON.stringify({"request": {"id": id}}); var text = JSON.stringify({"request": {"id": id}});
$.getJSON( $.getJSON(
"/api/" + $("#search-plugin").val() + "/add", "/api/" + $("#search-plugin").val() + "/add",
@ -253,6 +256,7 @@ window.OpenLP = {
history.back(); history.back();
} }
); );
$("#options").dialog("close");
return false; return false;
} }
} }
@ -274,6 +278,8 @@ $("#controller-unblank").live("click", OpenLP.unblankDisplay);
$("#alert-submit").live("click", OpenLP.showAlert); $("#alert-submit").live("click", OpenLP.showAlert);
// Search // Search
$("#search-submit").live("click", OpenLP.search); $("#search-submit").live("click", OpenLP.search);
$("#go-live").live("click", OpenLP.goLive);
$("#add-to-service").live("click", OpenLP.addToService);
// Poll the server twice a second to get any updates. // Poll the server twice a second to get any updates.
OpenLP.getSearchablePlugins(); OpenLP.getSearchablePlugins();
$.ajaxSetup({ cache: false }); $.ajaxSetup({ cache: false });

View File

@ -6,8 +6,8 @@
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman # # Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # # Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, #
# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # # Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, #
# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode # # Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode #
# Woldsund # # Woldsund #
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
@ -27,12 +27,13 @@
--> -->
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>OpenLP 2.0 Stage View</title> <title>${stage_title}</title>
<link rel="stylesheet" href="/files/stage.css" /> <link rel="stylesheet" href="/files/stage.css" />
<script type="text/javascript" src="/files/jquery.js"></script> <script type="text/javascript" src="/files/jquery.js"></script>
<script type="text/javascript" src="/files/stage.js"></script> <script type="text/javascript" src="/files/stage.js"></script>
</head> </head>
<body> <body>
<input type="hidden" id="next-text" value="${next}" />
<div id="right"> <div id="right">
<div id="clock"></div> <div id="clock"></div>
<div id="notes"></div> <div id="notes"></div>

View File

@ -100,24 +100,24 @@ window.OpenLP = {
$("#tag" + OpenLP.currentTags[OpenLP.currentSlide]).addClass("currenttag"); $("#tag" + OpenLP.currentTags[OpenLP.currentSlide]).addClass("currenttag");
var slide = OpenLP.currentSlides[OpenLP.currentSlide]; var slide = OpenLP.currentSlides[OpenLP.currentSlide];
var text = slide["text"]; var text = slide["text"];
text = text.replace(/\n/g, '<br />'); text = text.replace(/\n/g, "<br />");
$("#currentslide").html(text); $("#currentslide").html(text);
text = ""; text = "";
if (OpenLP.currentSlide < OpenLP.currentSlides.length - 1) { if (OpenLP.currentSlide < OpenLP.currentSlides.length - 1) {
for (var idx = OpenLP.currentSlide + 1; idx < OpenLP.currentSlides.length; idx++) { for (var idx = OpenLP.currentSlide + 1; idx < OpenLP.currentSlides.length; idx++) {
if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1]) if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1])
text = text + '<p class="nextslide">'; text = text + "<p class=\"nextslide\">";
text = text + OpenLP.currentSlides[idx]["text"]; text = text + OpenLP.currentSlides[idx]["text"];
if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1]) if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1])
text = text + '</p>'; text = text + "</p>";
else else
text = text + '<br />'; text = text + "<br />";
} }
text = text.replace(/\n/g, '<br />'); text = text.replace(/\n/g, "<br />");
$("#nextslide").html(text); $("#nextslide").html(text);
} }
else { else {
text = '<p class="nextslide">Next: ' + OpenLP.nextSong + '</p>'; text = "<p class=\"nextslide\">" + $("#next-text").val() + ": " + OpenLP.nextSong + "</p>";
$("#nextslide").html(text); $("#nextslide").html(text);
} }
}, },

View File

@ -115,7 +115,6 @@ import logging
import os import os
import urlparse import urlparse
import re import re
from pprint import pformat
try: try:
import json import json
@ -123,10 +122,11 @@ except ImportError:
import simplejson as json import simplejson as json
from PyQt4 import QtCore, QtNetwork from PyQt4 import QtCore, QtNetwork
from mako.template import Template
from openlp.core.lib import Receiver, PluginStatus from openlp.core.lib import Receiver, PluginStatus, StringContent
from openlp.core.ui import HideMode from openlp.core.ui import HideMode
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation, translate
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -154,12 +154,12 @@ class HttpServer(object):
e.g. http://localhost:4316/send/slidecontroller_live_next e.g. http://localhost:4316/send/slidecontroller_live_next
http://localhost:4316/send/alerts_text?q=your%20alert%20text http://localhost:4316/send/alerts_text?q=your%20alert%20text
""" """
def __init__(self, parent): def __init__(self, plugin):
""" """
Initialise the httpserver, and start the server Initialise the httpserver, and start the server
""" """
log.debug(u'Initialise httpserver') log.debug(u'Initialise httpserver')
self.parent = parent self.plugin = plugin
self.html_dir = os.path.join( self.html_dir = os.path.join(
AppLocation.get_directory(AppLocation.PluginsDir), AppLocation.get_directory(AppLocation.PluginsDir),
u'remotes', u'html') u'remotes', u'html')
@ -176,10 +176,10 @@ class HttpServer(object):
""" """
log.debug(u'Start TCP server') log.debug(u'Start TCP server')
port = QtCore.QSettings().value( port = QtCore.QSettings().value(
self.parent.settingsSection + u'/port', self.plugin.settingsSection + u'/port',
QtCore.QVariant(4316)).toInt()[0] QtCore.QVariant(4316)).toInt()[0]
address = QtCore.QSettings().value( address = QtCore.QSettings().value(
self.parent.settingsSection + u'/ip address', self.plugin.settingsSection + u'/ip address',
QtCore.QVariant(u'0.0.0.0')).toString() QtCore.QVariant(u'0.0.0.0')).toString()
self.server = QtNetwork.QTcpServer() self.server = QtNetwork.QTcpServer()
self.server.listen(QtNetwork.QHostAddress(address), port) self.server.listen(QtNetwork.QHostAddress(address), port)
@ -261,10 +261,11 @@ class HttpConnection(object):
self.ready_read) self.ready_read)
QtCore.QObject.connect(self.socket, QtCore.SIGNAL(u'disconnected()'), QtCore.QObject.connect(self.socket, QtCore.SIGNAL(u'disconnected()'),
self.disconnected) self.disconnected)
self.translate()
def _get_service_items(self): def _get_service_items(self):
service_items = [] service_items = []
service_manager = self.parent.parent.serviceManager service_manager = self.parent.plugin.serviceManager
if self.parent.current_item: if self.parent.current_item:
cur_uuid = self.parent.current_item._uuid cur_uuid = self.parent.current_item._uuid
else: else:
@ -280,6 +281,31 @@ class HttpConnection(object):
}) })
return service_items return service_items
def translate(self):
"""
Translate various strings in the mobile app.
"""
self.template_vars = {
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Remote'),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Stage View'),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
'search': translate('RemotePlugin.Mobile', 'Search'),
'back': translate('RemotePlugin.Mobile', 'Back'),
'refresh': translate('RemotePlugin.Mobile', 'Refresh'),
'blank': translate('RemotePlugin.Mobile', 'Blank'),
'show': translate('RemotePlugin.Mobile', 'Show'),
'prev': translate('RemotePlugin.Mobile', 'Prev'),
'next': translate('RemotePlugin.Mobile', 'Next'),
'text': translate('RemotePlugin.Mobile', 'Text'),
'show_alert': translate('RemotePlugin.Mobile', 'Show Alert'),
'go_live': translate('RemotePlugin.Mobile', 'Go Live'),
'add_to_service': translate('RemotePlugin.Mobile', 'Add To Service'),
'no_results': translate('RemotePlugin.Mobile', 'No Results'),
'options': translate('RemotePlugin.Mobile', 'Options')
}
def ready_read(self): def ready_read(self):
""" """
Data has been sent from the client. Respond to it Data has been sent from the client. Respond to it
@ -327,8 +353,11 @@ class HttpConnection(object):
if not path.startswith(self.parent.html_dir): if not path.startswith(self.parent.html_dir):
return HttpResponse(code=u'404 Not Found') return HttpResponse(code=u'404 Not Found')
ext = os.path.splitext(filename)[1] ext = os.path.splitext(filename)[1]
html = None
if ext == u'.html': if ext == u'.html':
mimetype = u'text/html' mimetype = u'text/html'
variables = self.template_vars
html = Template(filename=path, input_encoding=u'utf-8', output_encoding=u'utf-8').render(**variables)
elif ext == u'.css': elif ext == u'.css':
mimetype = u'text/css' mimetype = u'text/css'
elif ext == u'.js': elif ext == u'.js':
@ -343,6 +372,9 @@ class HttpConnection(object):
mimetype = u'text/plain' mimetype = u'text/plain'
file_handle = None file_handle = None
try: try:
if html:
content = html
else:
file_handle = open(path, u'rb') file_handle = open(path, u'rb')
log.debug(u'Opened %s' % path) log.debug(u'Opened %s' % path)
content = file_handle.read() content = file_handle.read()
@ -457,10 +489,11 @@ class HttpConnection(object):
""" """
if action == u'search': if action == u'search':
searches = [] searches = []
for plugin in self.parent.parent.pluginManager.plugins: for plugin in self.parent.plugin.pluginManager.plugins:
if plugin.status == PluginStatus.Active and \ if plugin.status == PluginStatus.Active and \
plugin.mediaItem and plugin.mediaItem.hasSearch: plugin.mediaItem and plugin.mediaItem.hasSearch:
searches.append(plugin.name) searches.append([plugin.name, unicode(
plugin.textStrings[StringContent.Name][u'plural'])])
return HttpResponse( return HttpResponse(
json.dumps({u'results': {u'items': searches}}), json.dumps({u'results': {u'items': searches}}),
{u'Content-Type': u'application/json'}) {u'Content-Type': u'application/json'})
@ -473,7 +506,7 @@ class HttpConnection(object):
The plugin name to search in. The plugin name to search in.
""" """
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and \ if plugin.status == PluginStatus.Active and \
plugin.mediaItem and plugin.mediaItem.hasSearch: plugin.mediaItem and plugin.mediaItem.hasSearch:
results = plugin.mediaItem.search(text) results = plugin.mediaItem.search(text)
@ -488,7 +521,7 @@ class HttpConnection(object):
Go live on an item of type ``type``. Go live on an item of type ``type``.
""" """
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem: if plugin.status == PluginStatus.Active and plugin.mediaItem:
plugin.mediaItem.goLive(id) plugin.mediaItem.goLive(id)
@ -497,7 +530,7 @@ class HttpConnection(object):
Add item of type ``type`` to the end of the service Add item of type ``type`` to the end of the service
""" """
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem: if plugin.status == PluginStatus.Active and plugin.mediaItem:
item_id = plugin.mediaItem.createItemFromId(id) item_id = plugin.mediaItem.createItemFromId(id)
plugin.mediaItem.addToService(item_id) plugin.mediaItem.addToService(item_id)

View File

@ -47,12 +47,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
""" """
log.info(u'%s EditSongForm loaded', __name__) log.info(u'%s EditSongForm loaded', __name__)
def __init__(self, parent, manager): def __init__(self, mediaitem, parent, manager):
""" """
Constructor Constructor
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.parent = parent self.mediaitem = mediaitem
self.song = None self.song = None
# can this be automated? # can this be automated?
self.width = 400 self.width = 400
@ -90,7 +90,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.onVerseListViewPressed) self.onVerseListViewPressed)
QtCore.QObject.connect(self.themeAddButton, QtCore.QObject.connect(self.themeAddButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.parent.parent.renderer.theme_manager.onAddTheme) self.mediaitem.plugin.renderer.theme_manager.onAddTheme)
QtCore.QObject.connect(self.maintenanceButton, QtCore.QObject.connect(self.maintenanceButton,
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked) QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
@ -649,7 +649,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
text = unicode(self.songBookComboBox.currentText()) text = unicode(self.songBookComboBox.currentText())
if item == 0 and text: if item == 0 and text:
temp_song_book = text temp_song_book = text
self.parent.song_maintenance_form.exec_() self.mediaitem.song_maintenance_form.exec_()
self.loadAuthors() self.loadAuthors()
self.loadBooks() self.loadBooks()
self.loadTopics() self.loadTopics()
@ -696,9 +696,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.clearCaches() self.clearCaches()
if self._validate_song(): if self._validate_song():
self.saveSong() self.saveSong()
Receiver.send_message(u'songs_set_autoselect_item', self.song = None
unicode(self.titleEdit.text()))
Receiver.send_message(u'songs_load_list')
QtGui.QDialog.accept(self) QtGui.QDialog.accept(self)
def saveSong(self, preview=False): def saveSong(self, preview=False):
@ -756,8 +754,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.song.topics.append(self.manager.get_object(Topic, topicId)) self.song.topics.append(self.manager.get_object(Topic, topicId))
clean_song(self.manager, self.song) clean_song(self.manager, self.song)
self.manager.save_object(self.song) self.manager.save_object(self.song)
if not preview: self.mediaitem.auto_select_id = self.song.id
self.song = None
def _processLyrics(self): def _processLyrics(self):
""" """

View File

@ -772,9 +772,9 @@ class SongImportForm(OpenLPWizard):
SettingsManager.get_last_dir(self.plugin.settingsSection, 1)) SettingsManager.get_last_dir(self.plugin.settingsSection, 1))
if not filename: if not filename:
return return
file = codecs.open(filename, u'w', u'utf-8') report_file = codecs.open(filename, u'w', u'utf-8')
file.write(self.errorReportTextEdit.toPlainText()) report_file.write(self.errorReportTextEdit.toPlainText())
file.close() report_file.close()
def addFileSelectItem(self, prefix, obj_prefix=None, can_disable=False, def addFileSelectItem(self, prefix, obj_prefix=None, can_disable=False,
single_select=False): single_select=False):

View File

@ -32,6 +32,9 @@ from openlp.core.lib import translate
from db import Author from db import Author
from ui import SongStrings from ui import SongStrings
WHITESPACE = re.compile(r'[\W_]+', re.UNICODE)
APOSTROPHE = re.compile(u'[\'`ʻ]', re.UNICODE)
class VerseType(object): class VerseType(object):
""" """
VerseType provides an enumeration for the tags that may be associated VerseType provides an enumeration for the tags that may be associated
@ -246,6 +249,12 @@ def retrieve_windows_encoding(recommendation=None):
return None return None
return filter(lambda item: item[1] == choice[0], encodings)[0][0] return filter(lambda item: item[1] == choice[0], encodings)[0][0]
def clean_string(string):
"""
Strips punctuation from the passed string to assist searching
"""
return WHITESPACE.sub(u' ', APOSTROPHE.sub(u'', string)).lower()
def clean_song(manager, song): def clean_song(manager, song):
""" """
Cleans the search title, rebuilds the search lyrics, adds a default author Cleans the search title, rebuilds the search lyrics, adds a default author
@ -262,20 +271,22 @@ def clean_song(manager, song):
if song.alternate_title is None: if song.alternate_title is None:
song.alternate_title = u'' song.alternate_title = u''
song.alternate_title = song.alternate_title.strip() song.alternate_title = song.alternate_title.strip()
whitespace = re.compile(r'\W+', re.UNICODE) song.search_title = clean_string(song.title) + u'@' + \
song.search_title = (whitespace.sub(u' ', song.title).strip() + u'@' + clean_string(song.alternate_title)
whitespace.sub(u' ', song.alternate_title).strip()).strip().lower() # Only do this, if we the song is a 1.9.4 song (or older).
# Remove the old "language" attribute from lyrics tag (prior to 1.9.5). This if song.lyrics.find(u'<lyrics language="en">') != -1:
# is not very important, but this keeps the database clean. This can be # Remove the old "language" attribute from lyrics tag (prior to 1.9.5).
# removed when everybody has cleaned his songs. # This is not very important, but this keeps the database clean. This
song.lyrics = song.lyrics.replace(u'<lyrics language="en">', u'<lyrics>') # can be removed when everybody has cleaned his songs.
song.lyrics = song.lyrics.replace(
u'<lyrics language="en">', u'<lyrics>')
verses = SongXML().get_verses(song.lyrics) verses = SongXML().get_verses(song.lyrics)
lyrics = u' '.join([whitespace.sub(u' ', verse[1]) for verse in verses]) song.search_lyrics = u' '.join([clean_string(verse[1])
song.search_lyrics = lyrics.lower() for verse in verses])
# We need a new and clean SongXML instance. # We need a new and clean SongXML instance.
sxml = SongXML() sxml = SongXML()
# Rebuild the song's verses, to remove any wrong verse names (for example # Rebuild the song's verses, to remove any wrong verse names (for
# translated ones), which might have been added prior to 1.9.5. # example translated ones), which might have been added prior to 1.9.5.
# List for later comparison. # List for later comparison.
compare_order = [] compare_order = []
for verse in verses: for verse in verses:
@ -300,9 +311,11 @@ def clean_song(manager, song):
order = [] order = []
new_order = [] new_order = []
for verse_def in order: for verse_def in order:
verse_type = VerseType.Tags[VerseType.from_loose_input(verse_def[0])] verse_type = VerseType.Tags[
VerseType.from_loose_input(verse_def[0])]
if len(verse_def) > 1: if len(verse_def) > 1:
new_order.append((u'%s%s' % (verse_type, verse_def[1:])).upper()) new_order.append(
(u'%s%s' % (verse_type, verse_def[1:])).upper())
else: else:
new_order.append(verse_type.upper()) new_order.append(verse_type.upper())
song.verse_order = u' '.join(new_order) song.verse_order = u' '.join(new_order)
@ -311,6 +324,11 @@ def clean_song(manager, song):
if order not in compare_order: if order not in compare_order:
song.verse_order = u'' song.verse_order = u''
break break
else:
verses = SongXML().get_verses(song.lyrics)
song.search_lyrics = u' '.join([clean_string(verse[1])
for verse in verses])
# The song does not have any author, add one. # The song does not have any author, add one.
if not song.authors: if not song.authors:
name = SongStrings.AuthorUnknown name = SongStrings.AuthorUnknown

View File

@ -165,7 +165,7 @@ def init_schema(url):
Column(u'id', types.Integer, primary_key=True), Column(u'id', types.Integer, primary_key=True),
Column(u'first_name', types.Unicode(128)), Column(u'first_name', types.Unicode(128)),
Column(u'last_name', types.Unicode(128)), Column(u'last_name', types.Unicode(128)),
Column(u'display_name', types.Unicode(255), nullable=False) Column(u'display_name', types.Unicode(255), index=True, nullable=False)
) )
# Definition of the "media_files" table # Definition of the "media_files" table
@ -186,7 +186,7 @@ def init_schema(url):
songs_table = Table(u'songs', metadata, songs_table = Table(u'songs', metadata,
Column(u'id', types.Integer, primary_key=True), Column(u'id', types.Integer, primary_key=True),
Column(u'song_book_id', types.Integer, Column(u'song_book_id', types.Integer,
ForeignKey(u'song_books.id'), default=0), ForeignKey(u'song_books.id'), default=None),
Column(u'title', types.Unicode(255), nullable=False), Column(u'title', types.Unicode(255), nullable=False),
Column(u'alternate_title', types.Unicode(255)), Column(u'alternate_title', types.Unicode(255)),
Column(u'lyrics', types.UnicodeText, nullable=False), Column(u'lyrics', types.UnicodeText, nullable=False),
@ -197,13 +197,13 @@ def init_schema(url):
Column(u'song_number', types.Unicode(64)), Column(u'song_number', types.Unicode(64)),
Column(u'theme_name', types.Unicode(128)), Column(u'theme_name', types.Unicode(128)),
Column(u'search_title', types.Unicode(255), index=True, nullable=False), Column(u'search_title', types.Unicode(255), index=True, nullable=False),
Column(u'search_lyrics', types.UnicodeText, index=True, nullable=False) Column(u'search_lyrics', types.UnicodeText, nullable=False)
) )
# Definition of the "topics" table # Definition of the "topics" table
topics_table = Table(u'topics', metadata, topics_table = Table(u'topics', metadata,
Column(u'id', types.Integer, primary_key=True), Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(128), nullable=False) Column(u'name', types.Unicode(128), index=True, nullable=False)
) )
# Definition of the "authors_songs" table # Definition of the "authors_songs" table
@ -230,27 +230,6 @@ def init_schema(url):
ForeignKey(u'topics.id'), primary_key=True) ForeignKey(u'topics.id'), primary_key=True)
) )
# Define table indexes
Index(u'authors_id', authors_table.c.id)
Index(u'authors_display_name_id', authors_table.c.display_name,
authors_table.c.id)
Index(u'media_files_id', media_files_table.c.id)
Index(u'song_books_id', song_books_table.c.id)
Index(u'songs_id', songs_table.c.id)
Index(u'topics_id', topics_table.c.id)
Index(u'authors_songs_author', authors_songs_table.c.author_id,
authors_songs_table.c.song_id)
Index(u'authors_songs_song', authors_songs_table.c.song_id,
authors_songs_table.c.author_id)
Index(u'media_files_songs_file', media_files_songs_table.c.media_file_id,
media_files_songs_table.c.song_id)
Index(u'media_files_songs_song', media_files_songs_table.c.song_id,
media_files_songs_table.c.media_file_id)
Index(u'topics_song_topic', songs_topics_table.c.topic_id,
songs_topics_table.c.song_id)
Index(u'topics_song_song', songs_topics_table.c.song_id,
songs_topics_table.c.topic_id)
mapper(Author, authors_table) mapper(Author, authors_table)
mapper(Book, song_books_table) mapper(Book, song_books_table)
mapper(MediaFile, media_files_table) mapper(MediaFile, media_files_table)

View File

@ -61,8 +61,8 @@ class EasiSlidesImport(SongImport):
""" """
log.info(u'Importing EasiSlides XML file %s', self.import_source) log.info(u'Importing EasiSlides XML file %s', self.import_source)
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
file = etree.parse(self.import_source, parser) parsed_file = etree.parse(self.import_source, parser)
xml = unicode(etree.tostring(file)) xml = unicode(etree.tostring(parsed_file))
song_xml = objectify.fromstring(xml) song_xml = objectify.fromstring(xml)
self.import_wizard.progressBar.setMaximum(len(song_xml.Item)) self.import_wizard.progressBar.setMaximum(len(song_xml.Item))
for song in song_xml.Item: for song in song_xml.Item:

View File

@ -27,6 +27,8 @@
""" """
The :mod:`importer` modules provides the general song import functionality. The :mod:`importer` modules provides the general song import functionality.
""" """
import logging
from opensongimport import OpenSongImport from opensongimport import OpenSongImport
from easislidesimport import EasiSlidesImport from easislidesimport import EasiSlidesImport
from olpimport import OpenLPSongImport from olpimport import OpenLPSongImport
@ -38,20 +40,24 @@ from songbeamerimport import SongBeamerImport
from songshowplusimport import SongShowPlusImport from songshowplusimport import SongShowPlusImport
from foilpresenterimport import FoilPresenterImport from foilpresenterimport import FoilPresenterImport
# Imports that might fail # Imports that might fail
log = logging.getLogger(__name__)
try: try:
from olp1import import OpenLP1SongImport from olp1import import OpenLP1SongImport
HAS_OPENLP1 = True HAS_OPENLP1 = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'OpenLP1SongImport')
HAS_OPENLP1 = False HAS_OPENLP1 = False
try: try:
from sofimport import SofImport from sofimport import SofImport
HAS_SOF = True HAS_SOF = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'SofImport')
HAS_SOF = False HAS_SOF = False
try: try:
from oooimport import OooImport from oooimport import OooImport
HAS_OOO = True HAS_OOO = True
except ImportError: except ImportError:
log.exception('Error importing %s', 'OooImport')
HAS_OOO = False HAS_OOO = False
class SongFormat(object): class SongFormat(object):

View File

@ -27,6 +27,7 @@
import logging import logging
import locale import locale
import re
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_ from sqlalchemy.sql import or_
@ -37,7 +38,8 @@ from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
clean_string
from openlp.plugins.songs.lib.db import Author, Song from openlp.plugins.songs.lib.db import Author, Song
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
@ -62,12 +64,13 @@ class SongMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon): def __init__(self, parent, plugin, icon):
self.IconPath = u'songs/song' self.IconPath = u'songs/song'
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
self.edit_song_form = EditSongForm(self, self.parent.manager) self.edit_song_form = EditSongForm(self, self.plugin.formparent,
self.openLyrics = OpenLyrics(self.parent.manager) self.plugin.manager)
self.openLyrics = OpenLyrics(self.plugin.manager)
self.singleServiceItem = False self.singleServiceItem = False
self.song_maintenance_form = SongMaintenanceForm( self.song_maintenance_form = SongMaintenanceForm(
self.parent.manager, self) self.plugin.manager, self)
# Holds information about whether the edit is remotly triggered and # Holds information about whether the edit is remotly triggered and
# which Song is required. # which Song is required.
self.remoteSong = -1 self.remoteSong = -1
@ -178,34 +181,35 @@ class SongMediaItem(MediaManagerItem):
self.displayResultsSong(search_results) self.displayResultsSong(search_results)
elif search_type == SongSearch.Titles: elif search_type == SongSearch.Titles:
log.debug(u'Titles Search') log.debug(u'Titles Search')
search_results = self.parent.manager.get_all_objects(Song, search_results = self.plugin.manager.get_all_objects(Song,
Song.search_title.like(u'%' + self.whitespace.sub(u' ', Song.search_title.like(u'%' + clean_string(search_keywords) +
search_keywords.lower()) + u'%')) u'%'))
self.displayResultsSong(search_results) self.displayResultsSong(search_results)
elif search_type == SongSearch.Lyrics: elif search_type == SongSearch.Lyrics:
log.debug(u'Lyrics Search') log.debug(u'Lyrics Search')
search_results = self.parent.manager.get_all_objects(Song, search_results = self.plugin.manager.get_all_objects(Song,
Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%')) Song.search_lyrics.like(u'%' + clean_string(search_keywords) +
u'%'))
self.displayResultsSong(search_results) self.displayResultsSong(search_results)
elif search_type == SongSearch.Authors: elif search_type == SongSearch.Authors:
log.debug(u'Authors Search') log.debug(u'Authors Search')
search_results = self.parent.manager.get_all_objects(Author, search_results = self.plugin.manager.get_all_objects(Author,
Author.display_name.like(u'%' + search_keywords + u'%'), Author.display_name.like(u'%' + search_keywords + u'%'),
Author.display_name.asc()) Author.display_name.asc())
self.displayResultsAuthor(search_results) self.displayResultsAuthor(search_results)
elif search_type == SongSearch.Themes: elif search_type == SongSearch.Themes:
log.debug(u'Theme Search') log.debug(u'Theme Search')
search_results = self.parent.manager.get_all_objects(Song, search_results = self.plugin.manager.get_all_objects(Song,
Song.theme_name.like(u'%' + self.whitespace.sub(u' ', Song.theme_name.like(u'%' + search_keywords + u'%'))
search_keywords) + u'%'))
self.displayResultsSong(search_results) self.displayResultsSong(search_results)
self.check_search_result() self.check_search_result()
def searchEntire(self, search_keywords): def searchEntire(self, search_keywords):
return self.parent.manager.get_all_objects(Song, return self.plugin.manager.get_all_objects(Song,
or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ', or_(Song.search_title.like(u'%' + clean_string(search_keywords)
search_keywords.lower()) + u'%'), + u'%'),
Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'), Song.search_lyrics.like(u'%' + clean_string(search_keywords)
+ u'%'),
Song.comments.like(u'%' + search_keywords.lower() + u'%'))) Song.comments.like(u'%' + search_keywords.lower() + u'%')))
def onSongListLoad(self): def onSongListLoad(self):
@ -225,13 +229,14 @@ class SongMediaItem(MediaManagerItem):
if self.editItem and self.updateServiceOnEdit and \ if self.editItem and self.updateServiceOnEdit and \
not self.remoteTriggered: not self.remoteTriggered:
item = self.buildServiceItem(self.editItem) item = self.buildServiceItem(self.editItem)
self.parent.serviceManager.replaceServiceItem(item) self.plugin.serviceManager.replaceServiceItem(item)
self.onRemoteEditClear() self.onRemoteEditClear()
self.onSearchTextButtonClick() self.onSearchTextButtonClick()
log.debug(u'onSongListLoad - finished') log.debug(u'onSongListLoad - finished')
def displayResultsSong(self, searchresults): def displayResultsSong(self, searchresults):
log.debug(u'display results Song') log.debug(u'display results Song')
self.save_auto_select_id()
self.listView.clear() self.listView.clear()
# Sort the songs by its title considering language specific characters. # Sort the songs by its title considering language specific characters.
# lower() is needed for windows! # lower() is needed for windows!
@ -245,8 +250,9 @@ class SongMediaItem(MediaManagerItem):
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id)) song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
self.listView.addItem(song_name) self.listView.addItem(song_name)
# Auto-select the item if name has been set # Auto-select the item if name has been set
if song.title == self.autoSelectItem : if song.id == self.auto_select_id:
self.listView.setCurrentItem(song_name) self.listView.setCurrentItem(song_name)
self.auto_select_id = -1
def displayResultsAuthor(self, searchresults): def displayResultsAuthor(self, searchresults):
log.debug(u'display results Author') log.debug(u'display results Author')
@ -284,18 +290,21 @@ class SongMediaItem(MediaManagerItem):
def onImportClick(self): def onImportClick(self):
if not hasattr(self, u'import_wizard'): if not hasattr(self, u'import_wizard'):
self.import_wizard = SongImportForm(self, self.parent) self.import_wizard = SongImportForm(self, self.plugin)
if self.import_wizard.exec_() == QtGui.QDialog.Accepted: if self.import_wizard.exec_() == QtGui.QDialog.Accepted:
Receiver.send_message(u'songs_load_list') Receiver.send_message(u'songs_load_list')
def onExportClick(self): def onExportClick(self):
export_wizard = SongExportForm(self, self.parent) export_wizard = SongExportForm(self, self.plugin)
export_wizard.exec_() export_wizard.exec_()
def onNewClick(self): def onNewClick(self):
log.debug(u'onNewClick') log.debug(u'onNewClick')
self.edit_song_form.newSong() self.edit_song_form.newSong()
self.edit_song_form.exec_() self.edit_song_form.exec_()
self.onClearTextButtonClick()
self.onSelectionChange()
self.auto_select_id = -1
def onSongMaintenanceClick(self): def onSongMaintenanceClick(self):
self.song_maintenance_form.exec_() self.song_maintenance_form.exec_()
@ -314,12 +323,14 @@ class SongMediaItem(MediaManagerItem):
log.debug(u'onRemoteEdit %s' % message) log.debug(u'onRemoteEdit %s' % message)
remote_type, song_id = message.split(u':') remote_type, song_id = message.split(u':')
song_id = int(song_id) song_id = int(song_id)
valid = self.parent.manager.get_object(Song, song_id) valid = self.plugin.manager.get_object(Song, song_id)
if valid: if valid:
self.remoteSong = song_id self.remoteSong = song_id
self.remoteTriggered = remote_type self.remoteTriggered = remote_type
self.edit_song_form.loadSong(song_id, (remote_type == u'P')) self.edit_song_form.loadSong(song_id, (remote_type == u'P'))
self.edit_song_form.exec_() self.edit_song_form.exec_()
self.auto_select_id = -1
self.onSongListLoad()
def onEditClick(self): def onEditClick(self):
""" """
@ -331,6 +342,8 @@ class SongMediaItem(MediaManagerItem):
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0] item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
self.edit_song_form.loadSong(item_id, False) self.edit_song_form.loadSong(item_id, False)
self.edit_song_form.exec_() self.edit_song_form.exec_()
self.auto_select_id = -1
self.onSongListLoad()
self.editItem = None self.editItem = None
def onDeleteClick(self): def onDeleteClick(self):
@ -350,7 +363,7 @@ class SongMediaItem(MediaManagerItem):
return return
for item in items: for item in items:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.parent.manager.delete_object(Song, item_id) self.plugin.manager.delete_object(Song, item_id)
self.onSearchTextButtonClick() self.onSearchTextButtonClick()
def generateSlideData(self, service_item, item=None, xmlVersion=False): def generateSlideData(self, service_item, item=None, xmlVersion=False):
@ -362,7 +375,7 @@ class SongMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.OnLoadUpdate) service_item.add_capability(ItemCapabilities.OnLoadUpdate)
service_item.add_capability(ItemCapabilities.AddIfNewItem) service_item.add_capability(ItemCapabilities.AddIfNewItem)
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit) service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
song = self.parent.manager.get_object(Song, item_id) song = self.plugin.manager.get_object(Song, item_id)
service_item.theme = song.theme_name service_item.theme = song.theme_name
service_item.edit_id = item_id service_item.edit_id = item_id
if song.lyrics.startswith(u'<?xml version='): if song.lyrics.startswith(u'<?xml version='):
@ -446,12 +459,12 @@ class SongMediaItem(MediaManagerItem):
# that the search title (data_string[u'title']) is probably wrong. # that the search title (data_string[u'title']) is probably wrong.
# We add "@" to search title and hope that we do not add any # We add "@" to search title and hope that we do not add any
# duplicate. This should work for songs without alternate title. # duplicate. This should work for songs without alternate title.
search_results = self.parent.manager.get_all_objects(Song, search_results = self.plugin.manager.get_all_objects(Song,
Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(u' ', Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(u' ',
item.data_string[u'title'].strip()) + u'@').strip().lower(), item.data_string[u'title'].strip()) + u'@').strip().lower(),
Song.search_title.asc()) Song.search_title.asc())
else: else:
search_results = self.parent.manager.get_all_objects(Song, search_results = self.plugin.manager.get_all_objects(Song,
Song.search_title == item.data_string[u'title'], Song.search_title == item.data_string[u'title'],
Song.search_title.asc()) Song.search_title.asc())
author_list = item.data_string[u'authors'].split(u', ') author_list = item.data_string[u'authors'].split(u', ')
@ -487,7 +500,4 @@ class SongMediaItem(MediaManagerItem):
Search for some songs Search for some songs
""" """
search_results = self.searchEntire(string) search_results = self.searchEntire(string)
results = [] return [[song.id, song.title] for song in search_results]
for song in search_results:
results.append([song.id, song.title])
return results

View File

@ -30,6 +30,7 @@ import os
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.utils import get_uno_command, get_uno_instance from openlp.core.utils import get_uno_command, get_uno_instance
from openlp.core.lib import translate
from songimport import SongImport from songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -39,8 +40,10 @@ if os.name == u'nt':
PAGE_BEFORE = 4 PAGE_BEFORE = 4
PAGE_AFTER = 5 PAGE_AFTER = 5
PAGE_BOTH = 6 PAGE_BOTH = 6
NoConnectException = Exception
else: else:
import uno import uno
from com.sun.star.connection import NoConnectException
from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH
class OooImport(SongImport): class OooImport(SongImport):
@ -57,7 +60,17 @@ class OooImport(SongImport):
self.process_started = False self.process_started = False
def do_import(self): def do_import(self):
if not isinstance(self.import_source, list):
return
try:
self.start_ooo() self.start_ooo()
except NoConnectException as exc:
self.log_error(
self.import_source[0],
translate('SongsPlugin.SongImport',
'Unable to open OpenOffice.org or LibreOffice'))
log.error(exc)
return
self.import_wizard.progressBar.setMaximum(len(self.import_source)) self.import_wizard.progressBar.setMaximum(len(self.import_source))
for filename in self.import_source: for filename in self.import_source:
if self.stop_import_flag: if self.stop_import_flag:
@ -68,6 +81,13 @@ class OooImport(SongImport):
if self.document: if self.document:
self.process_ooo_document() self.process_ooo_document()
self.close_ooo_file() self.close_ooo_file()
else:
self.log_error(self.filepath,
translate('SongsPlugin.SongImport',
'Unable to open file'))
else:
self.log_error(self.filepath,
translate('SongsPlugin.SongImport', 'File not found'))
self.close_ooo() self.close_ooo()
def process_ooo_document(self): def process_ooo_document(self):
@ -99,13 +119,16 @@ class OooImport(SongImport):
while uno_instance is None and loop < 5: while uno_instance is None and loop < 5:
try: try:
uno_instance = get_uno_instance(resolver) uno_instance = get_uno_instance(resolver)
except: except NoConnectException:
log.exception("Failed to resolve uno connection") log.exception("Failed to resolve uno connection")
self.start_ooo_process() self.start_ooo_process()
loop += 1 loop += 1
else:
manager = uno_instance.ServiceManager manager = uno_instance.ServiceManager
self.desktop = manager.createInstanceWithContext( self.desktop = manager.createInstanceWithContext(
"com.sun.star.frame.Desktop", uno_instance) "com.sun.star.frame.Desktop", uno_instance)
return
raise
def start_ooo_process(self): def start_ooo_process(self):
try: try:
@ -145,8 +168,8 @@ class OooImport(SongImport):
else: else:
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
u'Processing file ' + filepath, 0) u'Processing file ' + filepath, 0)
except: except AttributeError:
log.exception("open_ooo_file failed") log.exception("open_ooo_file failed: %s", url)
return return
def close_ooo_file(self): def close_ooo_file(self):

View File

@ -31,21 +31,27 @@
# http://www.oooforum.org/forum/viewtopic.phtml?t=14409 # http://www.oooforum.org/forum/viewtopic.phtml?t=14409
# http://wiki.services.openoffice.org/wiki/Python # http://wiki.services.openoffice.org/wiki/Python
import logging
import os import os
import re import re
from oooimport import OooImport from oooimport import OooImport
log = logging.getLogger(__name__)
if os.name == u'nt': if os.name == u'nt':
BOLD = 150.0 BOLD = 150.0
ITALIC = 2 ITALIC = 2
from oooimport import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH from oooimport import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH
RuntimeException = Exception
else: else:
try: try:
from com.sun.star.awt.FontWeight import BOLD from com.sun.star.awt.FontWeight import BOLD
from com.sun.star.awt.FontSlant import ITALIC from com.sun.star.awt.FontSlant import ITALIC
from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, \ from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, \
PAGE_BOTH PAGE_BOTH
from com.sun.star.uno import RuntimeException
except ImportError: except ImportError:
pass pass
@ -86,6 +92,7 @@ class SofImport(OooImport):
""" """
self.blanklines = 0 self.blanklines = 0
self.new_song() self.new_song()
try:
paragraphs = self.document.getText().createEnumeration() paragraphs = self.document.getText().createEnumeration()
while paragraphs.hasMoreElements(): while paragraphs.hasMoreElements():
if self.stop_import_flag: if self.stop_import_flag:
@ -93,9 +100,10 @@ class SofImport(OooImport):
paragraph = paragraphs.nextElement() paragraph = paragraphs.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"): if paragraph.supportsService("com.sun.star.text.Paragraph"):
self.process_paragraph(paragraph) self.process_paragraph(paragraph)
if self.song: except RuntimeException as exc:
self.finish() log.exception(u'Error processing file: %s', exc)
self.song = False if not self.finish():
self.log_error(self.filepath)
def process_paragraph(self, paragraph): def process_paragraph(self, paragraph):
""" """

View File

@ -514,7 +514,7 @@ class OpenLyrics(object):
``song`` ``song``
The song object. The song object.
""" """
song.song_book_id = 0 song.song_book_id = None
song.song_number = u'' song.song_number = u''
if hasattr(properties, u'songbooks'): if hasattr(properties, u'songbooks'):
for songbook in properties.songbooks.songbook: for songbook in properties.songbooks.songbook:

View File

@ -62,44 +62,44 @@ class SongUsagePlugin(Plugin):
""" """
log.info(u'add tools menu') log.info(u'add tools menu')
self.toolsMenu = tools_menu self.toolsMenu = tools_menu
self.SongUsageMenu = QtGui.QMenu(tools_menu) self.songUsageMenu = QtGui.QMenu(tools_menu)
self.SongUsageMenu.setObjectName(u'SongUsageMenu') self.songUsageMenu.setObjectName(u'songUsageMenu')
self.SongUsageMenu.setTitle(translate( self.songUsageMenu.setTitle(translate(
'SongUsagePlugin', '&Song Usage Tracking')) 'SongUsagePlugin', '&Song Usage Tracking'))
# SongUsage Delete # SongUsage Delete
self.SongUsageDelete = base_action(tools_menu, u'SongUsageDelete') self.songUsageDelete = base_action(tools_menu, u'songUsageDelete')
self.SongUsageDelete.setText(translate('SongUsagePlugin', self.songUsageDelete.setText(translate('SongUsagePlugin',
'&Delete Tracking Data')) '&Delete Tracking Data'))
self.SongUsageDelete.setStatusTip(translate('SongUsagePlugin', self.songUsageDelete.setStatusTip(translate('SongUsagePlugin',
'Delete song usage data up to a specified date.')) 'Delete song usage data up to a specified date.'))
# SongUsage Report # SongUsage Report
self.SongUsageReport = base_action(tools_menu, u'SongUsageReport') self.songUsageReport = base_action(tools_menu, u'songUsageReport')
self.SongUsageReport.setText( self.songUsageReport.setText(
translate('SongUsagePlugin', '&Extract Tracking Data')) translate('SongUsagePlugin', '&Extract Tracking Data'))
self.SongUsageReport.setStatusTip( self.songUsageReport.setStatusTip(
translate('SongUsagePlugin', 'Generate a report on song usage.')) translate('SongUsagePlugin', 'Generate a report on song usage.'))
# SongUsage activation # SongUsage activation
self.SongUsageStatus = shortcut_action(tools_menu, u'SongUsageStatus', self.songUsageStatus = shortcut_action(tools_menu, u'songUsageStatus',
[QtCore.Qt.Key_F4], self.toggleSongUsageState, checked=False) [QtCore.Qt.Key_F4], self.toggleSongUsageState, checked=False)
self.SongUsageStatus.setText(translate( self.songUsageStatus.setText(translate(
'SongUsagePlugin', 'Toggle Tracking')) 'SongUsagePlugin', 'Toggle Tracking'))
self.SongUsageStatus.setStatusTip(translate('SongUsagePlugin', self.songUsageStatus.setStatusTip(translate('SongUsagePlugin',
'Toggle the tracking of song usage.')) 'Toggle the tracking of song usage.'))
#Add Menus together #Add Menus together
self.toolsMenu.addAction(self.SongUsageMenu.menuAction()) self.toolsMenu.addAction(self.songUsageMenu.menuAction())
self.SongUsageMenu.addAction(self.SongUsageStatus) self.songUsageMenu.addAction(self.songUsageStatus)
self.SongUsageMenu.addSeparator() self.songUsageMenu.addSeparator()
self.SongUsageMenu.addAction(self.SongUsageDelete) self.songUsageMenu.addAction(self.songUsageDelete)
self.SongUsageMenu.addAction(self.SongUsageReport) self.songUsageMenu.addAction(self.songUsageReport)
# Signals and slots # Signals and slots
QtCore.QObject.connect(self.SongUsageStatus, QtCore.QObject.connect(self.songUsageStatus,
QtCore.SIGNAL(u'visibilityChanged(bool)'), QtCore.SIGNAL(u'visibilityChanged(bool)'),
self.SongUsageStatus.setChecked) self.songUsageStatus.setChecked)
QtCore.QObject.connect(self.SongUsageDelete, QtCore.QObject.connect(self.songUsageDelete,
QtCore.SIGNAL(u'triggered()'), self.onSongUsageDelete) QtCore.SIGNAL(u'triggered()'), self.onSongUsageDelete)
QtCore.QObject.connect(self.SongUsageReport, QtCore.QObject.connect(self.songUsageReport,
QtCore.SIGNAL(u'triggered()'), self.onSongUsageReport) QtCore.SIGNAL(u'triggered()'), self.onSongUsageReport)
self.SongUsageMenu.menuAction().setVisible(False) self.songUsageMenu.menuAction().setVisible(False)
def initialise(self): def initialise(self):
log.info(u'SongUsage Initialising') log.info(u'SongUsage Initialising')
@ -110,20 +110,20 @@ class SongUsagePlugin(Plugin):
self.SongUsageActive = QtCore.QSettings().value( self.SongUsageActive = QtCore.QSettings().value(
self.settingsSection + u'/active', self.settingsSection + u'/active',
QtCore.QVariant(False)).toBool() QtCore.QVariant(False)).toBool()
self.SongUsageStatus.setChecked(self.SongUsageActive) self.songUsageStatus.setChecked(self.SongUsageActive)
action_list = ActionList.get_instance() action_list = ActionList.get_instance()
action_list.add_action(self.SongUsageDelete, action_list.add_action(self.songUsageDelete,
translate('SongUsagePlugin', 'Song Usage')) translate('SongUsagePlugin', 'Song Usage'))
action_list.add_action(self.SongUsageReport, action_list.add_action(self.songUsageReport,
translate('SongUsagePlugin', 'Song Usage')) translate('SongUsagePlugin', 'Song Usage'))
action_list.add_action(self.SongUsageStatus, action_list.add_action(self.songUsageStatus,
translate('SongUsagePlugin', 'Song Usage')) translate('SongUsagePlugin', 'Song Usage'))
if self.manager is None: if self.manager is None:
self.manager = Manager(u'songusage', init_schema) self.manager = Manager(u'songusage', init_schema)
self.SongUsagedeleteform = SongUsageDeleteForm(self.manager, self.songUsageDeleteForm = SongUsageDeleteForm(self.manager,
self.formparent) self.formparent)
self.SongUsagedetailform = SongUsageDetailForm(self, self.formparent) self.songUsageDetailForm = SongUsageDetailForm(self, self.formparent)
self.SongUsageMenu.menuAction().setVisible(True) self.songUsageMenu.menuAction().setVisible(True)
def finalise(self): def finalise(self):
""" """
@ -132,13 +132,13 @@ class SongUsagePlugin(Plugin):
log.info(u'Plugin Finalise') log.info(u'Plugin Finalise')
self.manager.finalise() self.manager.finalise()
Plugin.finalise(self) Plugin.finalise(self)
self.SongUsageMenu.menuAction().setVisible(False) self.songUsageMenu.menuAction().setVisible(False)
action_list = ActionList.get_instance() action_list = ActionList.get_instance()
action_list.remove_action(self.SongUsageDelete, action_list.remove_action(self.songUsageDelete,
translate('SongUsagePlugin', 'Song Usage')) translate('SongUsagePlugin', 'Song Usage'))
action_list.remove_action(self.SongUsageReport, action_list.remove_action(self.songUsageReport,
translate('SongUsagePlugin', 'Song Usage')) translate('SongUsagePlugin', 'Song Usage'))
action_list.remove_action(self.SongUsageStatus, action_list.remove_action(self.songUsageStatus,
translate('SongUsagePlugin', 'Song Usage')) translate('SongUsagePlugin', 'Song Usage'))
#stop any events being processed #stop any events being processed
self.SongUsageActive = False self.SongUsageActive = False
@ -160,17 +160,15 @@ class SongUsagePlugin(Plugin):
song_usage_item.title = audit[0] song_usage_item.title = audit[0]
song_usage_item.copyright = audit[2] song_usage_item.copyright = audit[2]
song_usage_item.ccl_number = audit[3] song_usage_item.ccl_number = audit[3]
song_usage_item.authors = u'' song_usage_item.authors = u' '.join(audit[1])
for author in audit[1]:
song_usage_item.authors += author + u' '
self.manager.save_object(song_usage_item) self.manager.save_object(song_usage_item)
def onSongUsageDelete(self): def onSongUsageDelete(self):
self.SongUsagedeleteform.exec_() self.songUsageDeleteForm.exec_()
def onSongUsageReport(self): def onSongUsageReport(self):
self.SongUsagedetailform.initialise() self.songUsageDetailForm.initialise()
self.SongUsagedetailform.exec_() self.songUsageDetailForm.exec_()
def about(self): def about(self):
about_text = translate('SongUsagePlugin', '<strong>SongUsage Plugin' about_text = translate('SongUsagePlugin', '<strong>SongUsage Plugin'

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

View File

@ -24,6 +24,7 @@
<qresource prefix="bibles"> <qresource prefix="bibles">
<file>bibles_search_text.png</file> <file>bibles_search_text.png</file>
<file>bibles_search_reference.png</file> <file>bibles_search_reference.png</file>
<file>bibles_upgrade_alert.png</file>
<file>bibles_search_unlock.png</file> <file>bibles_search_unlock.png</file>
<file>bibles_search_lock.png</file> <file>bibles_search_lock.png</file>
</qresource> </qresource>

View File

@ -102,6 +102,13 @@ psvince.dll
the install will fail. The dll can be obtained from here: the install will fail. The dll can be obtained from here:
http://www.vincenzo.net/isxkb/index.php?title=PSVince) http://www.vincenzo.net/isxkb/index.php?title=PSVince)
Mako
Mako Templates for Python. This package is required for building the
remote plugin. It can be installed by going to your
python_directory\scripts\.. and running "easy_install Mako". If you do not
have easy_install, the Mako package can be obtained here:
http://www.makotemplates.org/download.html
""" """
import os import os
@ -194,7 +201,8 @@ def write_version_file():
code = bzr.wait() code = bzr.wait()
if code != 0: if code != 0:
raise Exception(u'Error running bzr log') raise Exception(u'Error running bzr log')
latest = output.split(u':')[0] outputAscii = unicode(output, errors='ignore')
latest = outputAscii.split(u':')[0]
versionstring = latest == revision and tag or u'%s-bzr%s' % (tag, latest) versionstring = latest == revision and tag or u'%s-bzr%s' % (tag, latest)
f = open(os.path.join(dist_path, u'.version'), u'w') f = open(os.path.join(dist_path, u'.version'), u'w')
f.write(versionstring) f.write(versionstring)