diff --git a/documentation/manual.txt b/documentation/manual.txt
new file mode 100644
index 000000000..55a3f7d98
--- /dev/null
+++ b/documentation/manual.txt
@@ -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.
diff --git a/openlp.pyw b/openlp.pyw
index f796fa45f..0bd7c940d 100755
--- a/openlp.pyw
+++ b/openlp.pyw
@@ -133,6 +133,8 @@ class OpenLP(QtGui.QApplication):
u'general/update check', QtCore.QVariant(True)).toBool()
if update_check:
VersionThread(self.mainWindow).start()
+ Receiver.send_message(u'maindisplay_blank_check')
+ self.mainWindow.appStartup()
DelayStartThread(self.mainWindow).start()
return self.exec_()
diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py
index 5b03e5fa4..3b7f633d9 100644
--- a/openlp/core/lib/db.py
+++ b/openlp/core/lib/db.py
@@ -32,8 +32,9 @@ import os
from PyQt4 import QtCore
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.pool import NullPool
from openlp.core.utils import AppLocation, delete_file
@@ -52,7 +53,7 @@ def init_db(url, auto_flush=True, auto_commit=False):
``auto_commit``
Sets the commit behaviour of the session
"""
- engine = create_engine(url)
+ engine = create_engine(url, poolclass=NullPool)
metadata = MetaData(bind=engine)
session = scoped_session(sessionmaker(autoflush=auto_flush,
autocommit=auto_commit, bind=engine))
diff --git a/openlp/core/lib/dockwidget.py b/openlp/core/lib/dockwidget.py
index 5c461bbf8..182b98c48 100644
--- a/openlp/core/lib/dockwidget.py
+++ b/openlp/core/lib/dockwidget.py
@@ -47,7 +47,6 @@ class OpenLPDockWidget(QtGui.QDockWidget):
"""
log.debug(u'Initialise the %s widget' % name)
QtGui.QDockWidget.__init__(self, parent)
- self.parent = parent
if name:
self.setObjectName(name)
if icon:
diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py
index 9b76447ff..e6083240e 100644
--- a/openlp/core/lib/mediamanageritem.py
+++ b/openlp/core/lib/mediamanageritem.py
@@ -90,11 +90,10 @@ class MediaManagerItem(QtGui.QWidget):
"""
Constructor to create the media manager item.
"""
- QtGui.QWidget.__init__(self)
- self.parent = parent
- self.whitespace = re.compile(r'\W+', re.UNICODE)
- #TODO: plugin should not be the parent in future
- self.plugin = parent # plugin
+ QtGui.QWidget.__init__(self, parent)
+ self.hide()
+ self.whitespace = re.compile(r'[\W_]+', re.UNICODE)
+ self.plugin = plugin
visible_title = self.plugin.getString(StringContent.VisibleName)
self.title = unicode(visible_title[u'title'])
self.settingsSection = self.plugin.name.lower()
@@ -112,13 +111,10 @@ class MediaManagerItem(QtGui.QWidget):
self.requiredIcons()
self.setupUi()
self.retranslateUi()
- self.autoSelectItem = None
+ self.auto_select_id = -1
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)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'%s_set_autoselect_item' % self.parent.name.lower()),
- self.setAutoSelectItem)
def requiredIcons(self):
"""
@@ -458,7 +454,8 @@ class MediaManagerItem(QtGui.QWidget):
"""
if QtCore.QSettings().value(u'advanced/single click preview',
QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \
- and self.listView.selectedIndexes():
+ and self.listView.selectedIndexes() \
+ and self.auto_select_id == -1:
self.onPreviewClick(True)
def onPreviewClick(self, keepFocus=False):
@@ -475,13 +472,10 @@ class MediaManagerItem(QtGui.QWidget):
serviceItem = self.buildServiceItem()
if serviceItem:
serviceItem.from_plugin = True
- self.parent.previewController.addServiceItem(serviceItem)
+ self.plugin.previewController.addServiceItem(serviceItem)
if keepFocus:
self.listView.setFocus()
- def setAutoSelectItem(self, itemToSelect=None):
- self.autoSelectItem = itemToSelect
-
def onLiveClick(self):
"""
Send an item live by building a service item then adding that service
@@ -503,7 +497,7 @@ class MediaManagerItem(QtGui.QWidget):
if serviceItem:
if not item_id:
serviceItem.from_plugin = True
- self.parent.liveController.addServiceItem(serviceItem)
+ self.plugin.liveController.addServiceItem(serviceItem)
def createItemFromId(self, item_id):
item = QtGui.QListWidgetItem()
@@ -533,7 +527,7 @@ class MediaManagerItem(QtGui.QWidget):
serviceItem = self.buildServiceItem(item, True)
if serviceItem:
serviceItem.from_plugin = False
- self.parent.serviceManager.addServiceItem(serviceItem,
+ self.plugin.serviceManager.addServiceItem(serviceItem,
replace=replace)
def onAddEditClick(self):
@@ -546,14 +540,14 @@ class MediaManagerItem(QtGui.QWidget):
'You must select one or more items.'))
else:
log.debug(u'%s Add requested', self.plugin.name)
- serviceItem = self.parent.serviceManager.getServiceItem()
+ serviceItem = self.plugin.serviceManager.getServiceItem()
if not serviceItem:
QtGui.QMessageBox.information(self, UiStrings().NISs,
translate('OpenLP.MediaManagerItem',
'You must select an existing service item to add to.'))
elif self.plugin.name.lower() == serviceItem.name.lower():
self.generateSlideData(serviceItem)
- self.parent.serviceManager.addServiceItem(serviceItem,
+ self.plugin.serviceManager.addServiceItem(serviceItem,
replace=True)
else:
# Turn off the remote edit update message indicator
@@ -567,8 +561,8 @@ class MediaManagerItem(QtGui.QWidget):
"""
Common method for generating a service item
"""
- serviceItem = ServiceItem(self.parent)
- serviceItem.add_icon(self.parent.icon_path)
+ serviceItem = ServiceItem(self.plugin)
+ serviceItem.add_icon(self.plugin.icon_path)
if self.generateSlideData(serviceItem, item, xmlVersion):
return serviceItem
else:
@@ -617,6 +611,16 @@ class MediaManagerItem(QtGui.QWidget):
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
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):
"""
Performs a plugin specific search for items containing ``string``
diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py
index 0417446c1..910c52d2c 100644
--- a/openlp/core/lib/plugin.py
+++ b/openlp/core/lib/plugin.py
@@ -215,7 +215,8 @@ class Plugin(QtCore.QObject):
you need, and return it for integration into openlp.org.
"""
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
def addImportMenuItem(self, importMenu):
@@ -299,6 +300,12 @@ class Plugin(QtCore.QObject):
if self.mediaItem:
self.mediadock.remove_dock(self.mediaItem)
+ def appStartup(self):
+ """
+ Perform tasks on application starup
+ """
+ pass
+
def usesTheme(self, theme):
"""
Called to find out if a plugin is currently using a theme.
diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py
index 079a9aa9c..c6e729be8 100644
--- a/openlp/core/lib/renderer.py
+++ b/openlp/core/lib/renderer.py
@@ -67,7 +67,7 @@ class Renderer(object):
``theme_manager``
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.image_manager = image_manager
self.screens = ScreenList.get_instance()
@@ -77,7 +77,7 @@ class Renderer(object):
self.theme_data = None
self.bg_frame = None
self.force_page = False
- self.display = MainDisplay(self, self.image_manager, False)
+ self.display = MainDisplay(None, self.image_manager, False)
self.display.setup()
def update_display(self):
@@ -86,7 +86,7 @@ class Renderer(object):
"""
log.debug(u'Update Display')
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.bg_frame = None
self.theme_data = None
diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/displaytagform.py
index 6aaddf2b8..4b25f851a 100644
--- a/openlp/core/ui/displaytagform.py
+++ b/openlp/core/ui/displaytagform.py
@@ -147,6 +147,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
DisplayTags.remove_html_tag(self.selected)
self.selected = -1
self._resetTable()
+ self._saveTable()
def onSavedPushed(self):
"""
@@ -171,14 +172,19 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
html[u'end tag'] = u'{/%s}' % tag
self.selected = -1
self._resetTable()
- temp = []
+ self._saveTable()
+
+ def _saveTable(self):
+ """
+ Saves all display tags except protected ones.
+ """
+ tags = []
for tag in DisplayTags.get_html_tags():
if not tag[u'protected']:
- temp.append(tag)
- if temp:
- ctemp = cPickle.dumps(temp)
+ tags.append(tag)
+ if tags:
QtCore.QSettings().setValue(u'displayTags/html_tags',
- QtCore.QVariant(ctemp))
+ QtCore.QVariant(cPickle.dumps(tags)))
else:
QtCore.QSettings().setValue(u'displayTags/html_tags',
QtCore.QVariant(u''))
diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py
index 69f3c14af..f240561ff 100644
--- a/openlp/core/ui/exceptionform.py
+++ b/openlp/core/ui/exceptionform.py
@@ -106,7 +106,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
"""
Saving exception log and system informations to a file.
"""
- report = unicode(translate('OpenLP.ExceptionForm',
+ report_text = unicode(translate('OpenLP.ExceptionForm',
'**OpenLP Bug Report**\n'
'Version: %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))
SettingsManager.set_last_dir(self.settingsSection, os.path.dirname(
filename))
- report = report % self._createReport()
+ report_text = report_text % self._createReport()
try:
- file = open(filename, u'w')
+ report_file = open(filename, u'w')
try:
- file.write(report)
+ report_file.write(report_text)
except UnicodeError:
- file.close()
- file = open(filename, u'wb')
- file.write(report.encode(u'utf-8'))
+ report_file.close()
+ report_file = open(filename, u'wb')
+ report_file.write(report_text.encode(u'utf-8'))
finally:
- file.close()
+ report_file.close()
except IOError:
log.exception(u'Failed to write crash report')
finally:
- file.close()
+ report_file.close()
def onSendReportButtonPressed(self):
"""
diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py
index 2435b8dcc..2a9bd221e 100644
--- a/openlp/core/ui/generaltab.py
+++ b/openlp/core/ui/generaltab.py
@@ -223,9 +223,9 @@ class GeneralTab(SettingsTab):
self.autoPreviewCheckBox.setText(translate('OpenLP.GeneralTab',
'Automatically preview next item in service'))
self.enableLoopCheckBox.setText(translate('OpenLP.GeneralTab',
- 'Enable slide loop'))
+ 'Enable slide wrap-around'))
self.timeoutLabel.setText(translate('OpenLP.GeneralTab',
- 'Slide loop delay:'))
+ 'Timed slide interval:'))
self.timeoutSpinBox.setSuffix(translate('OpenLP.GeneralTab', ' sec'))
self.ccliGroupBox.setTitle(
translate('OpenLP.GeneralTab', 'CCLI Details'))
diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py
index dc7c28ded..e2117cc10 100644
--- a/openlp/core/ui/maindisplay.py
+++ b/openlp/core/ui/maindisplay.py
@@ -49,8 +49,7 @@ class MainDisplay(QtGui.QGraphicsView):
This is the display screen.
"""
def __init__(self, parent, image_manager, live):
- QtGui.QGraphicsView.__init__(self)
- self.parent = parent
+ QtGui.QGraphicsView.__init__(self, parent)
self.isLive = live
self.image_manager = image_manager
self.screens = ScreenList.get_instance()
@@ -149,7 +148,6 @@ class MainDisplay(QtGui.QGraphicsView):
self.__hideMouse()
# To display or not to display?
if not self.screen[u'primary']:
- self.show()
self.primary = False
else:
self.primary = True
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index 82f1b9253..b4a3b3640 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -179,7 +179,7 @@ class Ui_MainWindow(object):
u'printServiceItem', [QtGui.QKeySequence(u'Ctrl+P')],
self.serviceManagerContents.printServiceOrder,
category=UiStrings().File)
- self.fileExitItem = shortcut_action(mainWindow, u'FileExitItem',
+ self.fileExitItem = shortcut_action(mainWindow, u'fileExitItem',
[QtGui.QKeySequence(u'Alt+F4')], mainWindow.close,
u':/system/system_exit.png', category=UiStrings().File)
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.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):
# Import themes if first time
Receiver.send_message(u'openlp_process_events')
@@ -669,13 +678,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def blankCheck(self):
"""
Check and display message if screen blank on setup.
- Triggered by delay thread.
"""
settings = QtCore.QSettings()
+ self.liveController.mainDisplaySetBackground()
if settings.value(u'%s/screen blank' % self.generalSettingsSection,
QtCore.QVariant(False)).toBool():
- self.liveController.mainDisplaySetBackground()
- if settings.value(u'blank warning',
+ if settings.value(u'%s/blank warning' % self.generalSettingsSection,
QtCore.QVariant(False)).toBool():
QtGui.QMessageBox.question(self,
translate('OpenLP.MainWindow',
diff --git a/openlp/core/ui/pluginform.py b/openlp/core/ui/pluginform.py
index 0f7f6dbeb..b4c87488c 100644
--- a/openlp/core/ui/pluginform.py
+++ b/openlp/core/ui/pluginform.py
@@ -40,7 +40,6 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
"""
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
- self.parent = parent
self.activePlugin = None
self.programaticChange = False
self.setupUi(self)
@@ -65,7 +64,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self._clearDetails()
self.programaticChange = True
pluginListWidth = 0
- for plugin in self.parent.pluginManager.plugins:
+ for plugin in self.parent().pluginManager.plugins:
item = QtGui.QListWidgetItem(self.pluginListWidget)
# 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.
@@ -117,7 +116,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
plugin_name_singular = \
self.pluginListWidget.currentItem().text().split(u' ')[0]
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:
self.activePlugin = plugin
break
@@ -133,6 +132,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
Receiver.send_message(u'cursor_busy')
self.activePlugin.toggleStatus(PluginStatus.Active)
Receiver.send_message(u'cursor_normal')
+ self.activePlugin.appStartup()
else:
self.activePlugin.toggleStatus(PluginStatus.Inactive)
status_text = unicode(
diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py
index 09ae8857f..ccd1eb18c 100644
--- a/openlp/core/ui/printserviceform.py
+++ b/openlp/core/ui/printserviceform.py
@@ -42,42 +42,44 @@ http://doc.trolltech.com/4.7/richtext-html-subset.html#css-properties
*/
.serviceTitle {
- font-weight:600;
- font-size:x-large;
- color:black;
+ font-weight: 600;
+ font-size: x-large;
+ color: black;
}
.item {
- color:black;
+ color: black;
}
.itemTitle {
- font-weight:600;
- font-size:large;
+ font-weight: 600;
+ font-size: large;
}
-.itemText {}
+.itemText {
+ margin-top: 10px;
+}
.itemFooter {
- font-size:8px;
+ font-size: 8px;
}
.itemNotes {}
.itemNotesTitle {
- font-weight:bold;
- font-size:12px;
+ font-weight: bold;
+ font-size: 12px;
}
.itemNotesText {
- font-size:11px;
+ font-size: 11px;
}
.media {}
.mediaTitle {
- font-weight:bold;
- font-size:11px;
+ font-weight: bold;
+ font-size: 11px;
}
.mediaText {}
@@ -89,16 +91,16 @@ http://doc.trolltech.com/4.7/richtext-html-subset.html#css-properties
}
.customNotesTitle {
- font-weight:bold;
- font-size:11px;
+ font-weight: bold;
+ font-size: 11px;
}
.customNotesText {
- font-size:11px;
+ font-size: 11px;
}
.newPage {
- page-break-before:always;
+ page-break-before: always;
}
"""
@@ -212,11 +214,11 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
verse_def = None
for slide in item.get_frames():
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')
else:
- self._addElement(u'br', parent=p)
- self._addElement(u'p', slide[u'html'], p)
+ self._addElement(u'br', parent=text_div)
+ self._addElement(u'span', slide[u'html'], text_div)
verse_def = slide[u'verseTag']
# Break the page before the div element.
if index != 0 and self.pageBreakAfterText.isChecked():
diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py
index 2b6e10644..160080c5a 100644
--- a/openlp/core/ui/screen.py
+++ b/openlp/core/ui/screen.py
@@ -79,7 +79,7 @@ class ScreenList(object):
``number``
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:
if number == screen[u'number']:
newScreen = {
@@ -104,6 +104,9 @@ class ScreenList(object):
``changed_screen``
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.
for screen in copy.deepcopy(self.screen_list):
if screen[u'number'] == self.desktop.numScreens():
@@ -116,8 +119,7 @@ class ScreenList(object):
u'size': self.desktop.screenGeometry(number),
u'primary': (self.desktop.primaryScreen() == number)
})
- # We do not want to send this message, when the method is called the
- # first time.
+ # We do not want to send this message at start up.
if changed_screen != -1:
# Reload setting tabs to apply possible changes.
Receiver.send_message(u'config_screen_changed')
@@ -241,6 +243,7 @@ class ScreenList(object):
height = settings.value(u'height',
QtCore.QVariant(self.current[u'size'].height())).toInt()[0]
self.override[u'size'] = QtCore.QRect(x, y, width, height)
+ self.override[u'primary'] = False
settings.endGroup()
if override_display:
self.set_override_display()
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index 7851e5e41..8ecd89bc7 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -676,8 +676,18 @@ class ServiceManager(QtGui.QWidget):
.is_capable(ItemCapabilities.AllowsVariableStartTime):
self.timeAction.setVisible(True)
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)
+ # 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))
def onServiceItemNoteForm(self):
@@ -949,6 +959,7 @@ class ServiceManager(QtGui.QWidget):
treewidgetitem.setToolTip(0, serviceitem.notes)
treewidgetitem.setData(0, QtCore.Qt.UserRole,
QtCore.QVariant(item[u'order']))
+ treewidgetitem.setSelected(item[u'selected'])
# Add the children to their parent treewidgetitem.
for count, frame in enumerate(serviceitem.get_frames()):
child = QtGui.QTreeWidgetItem(treewidgetitem)
@@ -1020,16 +1031,34 @@ class ServiceManager(QtGui.QWidget):
# force reset of renderer as theme data has changed
self.mainwindow.renderer.themedata = None
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
self.serviceManagerList.clear()
self.serviceItems = []
self.isNew = True
for item in tempServiceItems:
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
# does not impact the saved song so True may also be valid
self.setModified()
+ # Repaint it once only at the end
+ self.repaintServiceList(-1, -1)
Receiver.send_message(u'cursor_normal')
def serviceItemUpdate(self, message):
@@ -1059,7 +1088,7 @@ class ServiceManager(QtGui.QWidget):
self.setModified()
def addServiceItem(self, item, rebuild=False, expand=None, replace=False,
- repaint=True):
+ repaint=True, selected=False):
"""
Add a Service item to the list
@@ -1087,17 +1116,17 @@ class ServiceManager(QtGui.QWidget):
for inditem in item:
self.serviceItems.append({u'service_item': inditem,
u'order': len(self.serviceItems) + 1,
- u'expanded': expand})
+ u'expanded': expand, u'selected': selected})
else:
self.serviceItems.append({u'service_item': item,
u'order': len(self.serviceItems) + 1,
- u'expanded': expand})
+ u'expanded': expand, u'selected': selected})
if repaint:
self.repaintServiceList(len(self.serviceItems) - 1, -1)
else:
self.serviceItems.insert(self.dropPosition,
{u'service_item': item, u'order': self.dropPosition,
- u'expanded': expand})
+ u'expanded': expand, u'selected': selected})
self.repaintServiceList(self.dropPosition, -1)
# if rebuilding list make sure live is fixed.
if rebuild:
@@ -1280,16 +1309,33 @@ class ServiceManager(QtGui.QWidget):
self.themeComboBox.clear()
self.themeMenu.clear()
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:
self.themeComboBox.addItem(theme)
- context_menu_action(self.themeMenu, None, theme,
+ themeAction = context_menu_action(self.themeMenu, None, theme,
self.onThemeChangeAction)
+ themeAction.setObjectName(theme)
+ themeAction.setCheckable(True)
+ themeGroup.addAction(themeAction)
find_and_set_in_combo_box(self.themeComboBox, self.service_theme)
self.mainwindow.renderer.set_service_theme(self.service_theme)
self.regenerateServiceItems()
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]
self.serviceItems[item][u'service_item'].theme = theme
self.regenerateServiceItems()
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index b1094bbe3..5b6212cf8 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -46,7 +46,6 @@ class SlideList(QtGui.QTableWidget):
"""
def __init__(self, parent=None, name=None):
QtGui.QTableWidget.__init__(self, parent.controller)
- self.parent = parent
class SlideController(QtGui.QWidget):
@@ -60,13 +59,12 @@ class SlideController(QtGui.QWidget):
"""
QtGui.QWidget.__init__(self, parent)
self.isLive = isLive
- self.parent = parent
self.screens = ScreenList.get_instance()
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
- self.image_manager = self.parent.image_manager
+ self.image_manager = self.parent().image_manager
self.loopList = [
- u'Start Loop',
+ u'Play Slides Menu',
u'Loop Separator',
u'Image SpinBox'
]
@@ -140,19 +138,20 @@ class SlideController(QtGui.QWidget):
self.previousItem = self.toolbar.addToolbarButton(
translate('OpenLP.SlideController', 'Previous Slide'),
u':/slides/slide_previous.png',
- translate('OpenLP.SlideController', 'Move to previous'),
+ translate('OpenLP.SlideController', 'Move to previous.'),
self.onSlideSelectedPrevious,
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
context=QtCore.Qt.WidgetWithChildrenShortcut)
self.nextItem = self.toolbar.addToolbarButton(
translate('OpenLP.SlideController', 'Next Slide'),
u':/slides/slide_next.png',
- translate('OpenLP.SlideController', 'Move to next'),
+ translate('OpenLP.SlideController', 'Move to next.'),
self.onSlideSelectedNext,
shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
context=QtCore.Qt.WidgetWithChildrenShortcut)
self.toolbar.addToolbarSeparator(u'Close Separator')
if self.isLive:
+ # Hide Menu
self.hideMenu = QtGui.QToolButton(self.toolbar)
self.hideMenu.setText(translate('OpenLP.SlideController', 'Hide'))
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.desktopScreen)
self.toolbar.addToolbarSeparator(u'Loop Separator')
- startLoop = self.toolbar.addToolbarButton(
- # Does not need translating - control string.
- u'Start Loop', u':/media/media_time.png',
- translate('OpenLP.SlideController', 'Start continuous loop'),
- self.onStartLoop)
- startLoop.setObjectName(u'startLoop')
- action_list = ActionList.get_instance()
- action_list.add_action(startLoop, UiStrings().LiveToolbar)
- stopLoop = self.toolbar.addToolbarButton(
- # Does not need translating - control string.
- u'Stop Loop', u':/media/media_stop.png',
- translate('OpenLP.SlideController', 'Stop continuous loop'),
- self.onStopLoop)
- stopLoop.setObjectName(u'stopLoop')
- action_list.add_action(stopLoop, UiStrings().LiveToolbar)
- self.toogleLoop = shortcut_action(self, u'toogleLoop',
- [QtGui.QKeySequence(u'L')], self.onToggleLoop,
- category=UiStrings().LiveToolbar)
- self.toogleLoop.setText(translate('OpenLP.SlideController',
- 'Start/Stop continuous loop'))
- self.addAction(self.toogleLoop)
+ # Play Slides Menu
+ self.playSlidesMenu = QtGui.QToolButton(self.toolbar)
+ self.playSlidesMenu.setText(translate('OpenLP.SlideController',
+ 'Play Slides'))
+ self.playSlidesMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
+ self.toolbar.addToolbarWidget(u'Play Slides Menu',
+ self.playSlidesMenu)
+ self.playSlidesMenu.setMenu(QtGui.QMenu(
+ translate('OpenLP.SlideController', 'Play Slides'),
+ self.toolbar))
+ self.playSlidesLoop = shortcut_action(self.playSlidesMenu,
+ u'playSlidesLoop', [], self.onPlaySlidesLoop,
+ u':/media/media_time.png', False, UiStrings().LiveToolbar)
+ self.playSlidesLoop.setText(
+ translate('OpenLP.SlideController', 'Play Slides in Loop'))
+ self.playSlidesOnce = shortcut_action(self.playSlidesMenu,
+ u'playSlidesOnce', [], self.onPlaySlidesOnce,
+ u':/media/media_time.png', False, UiStrings().LiveToolbar)
+ self.playSlidesOnce.setText(
+ translate('OpenLP.SlideController', 'Play Slides to End'))
+ 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.setRange(1, 180)
self.toolbar.addToolbarWidget(u'Image SpinBox', self.delaySpinBox)
self.delaySpinBox.setSuffix(UiStrings().Seconds)
self.delaySpinBox.setToolTip(translate('OpenLP.SlideController',
- 'Delay between slides in seconds'))
+ 'Delay between slides in seconds.'))
else:
self.toolbar.addToolbarButton(
# Does not need translating - control string.
u'Go Live', u':/general/general_live.png',
- translate('OpenLP.SlideController', 'Move to live'),
+ translate('OpenLP.SlideController', 'Move to live.'),
self.onGoLive)
self.toolbar.addToolbarButton(
# Does not need translating - control string.
u'Add to Service', u':/general/general_add.png',
- translate('OpenLP.SlideController', 'Add to Service'),
+ translate('OpenLP.SlideController', 'Add to Service.'),
self.onPreviewAddToService)
self.toolbar.addToolbarSeparator(u'Close Separator')
self.toolbar.addToolbarButton(
# Does not need translating - control string.
u'Edit Song', u':/general/general_edit.png',
translate('OpenLP.SlideController',
- 'Edit and reload song preview'),
+ 'Edit and reload song preview.'),
self.onEditSong)
self.controllerLayout.addWidget(self.toolbar)
# Build a Media ToolBar
self.mediabar = OpenLPToolbar(self)
self.mediabar.addToolbarButton(
u'Media Start', u':/slides/media_playback_start.png',
- translate('OpenLP.SlideController', 'Start playing media'),
+ translate('OpenLP.SlideController', 'Start playing media.'),
self.onMediaPlay)
self.mediabar.addToolbarButton(
u'Media Pause', u':/slides/media_playback_pause.png',
- translate('OpenLP.SlideController', 'Start playing media'),
+ translate('OpenLP.SlideController', 'Start playing media.'),
self.onMediaPause)
self.mediabar.addToolbarButton(
u'Media Stop', u':/slides/media_playback_stop.png',
- translate('OpenLP.SlideController', 'Start playing media'),
+ translate('OpenLP.SlideController', 'Start playing media.'),
self.onMediaStop)
if self.isLive:
# Build the Song Toolbar
@@ -321,7 +327,6 @@ class SlideController(QtGui.QWidget):
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
self.receiveSpinDelay)
self.toolbar.makeWidgetsInvisible(self.loopList)
- self.toolbar.actions[u'Stop Loop'].setVisible(False)
else:
QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
@@ -461,7 +466,7 @@ class SlideController(QtGui.QWidget):
self.previewListWidget.resizeRowsToContents()
else:
# 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())):
self.previewListWidget.setRowHeight(
framenumber, width / self.ratio)
@@ -496,21 +501,14 @@ class SlideController(QtGui.QWidget):
self.mediabar.setVisible(False)
self.toolbar.makeWidgetsInvisible([u'Song Menu'])
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 QtCore.QSettings().value(
- self.parent.songsSettingsSection + u'/display songbar',
+ self.parent().songsSettingsSection + u'/display songbar',
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
self.toolbar.makeWidgetsVisible([u'Song Menu'])
if item.is_capable(ItemCapabilities.AllowsLoop) and \
len(item.get_frames()) > 1:
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():
self.toolbar.setVisible(False)
self.mediabar.setVisible(True)
@@ -591,7 +589,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_start' % serviceItem.name.lower(),
[serviceItem, self.isLive, self.hideMode(), slideno])
self.slideList = {}
- width = self.parent.controlSplitter.sizes()[self.split]
+ width = self.parent().controlSplitter.sizes()[self.split]
self.previewListWidget.clear()
self.previewListWidget.setRowCount(0)
self.previewListWidget.setColumnWidth(0, width)
@@ -625,8 +623,8 @@ class SlideController(QtGui.QWidget):
label.setScaledContents(True)
if self.serviceItem.is_command():
image = resize_image(frame[u'image'],
- self.parent.renderer.width,
- self.parent.renderer.height)
+ self.parent().renderer.width,
+ self.parent().renderer.height)
else:
# If current slide set background to image
if framenumber == slideno:
@@ -635,7 +633,7 @@ class SlideController(QtGui.QWidget):
image = self.image_manager.get_image(frame[u'title'])
label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label)
- slideHeight = width * self.parent.renderer.screen_ratio
+ slideHeight = width * self.parent().renderer.screen_ratio
row += 1
text.append(unicode(row))
self.previewListWidget.setItem(framenumber, 0, item)
@@ -736,7 +734,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
display_type = QtCore.QSettings().value(
- self.parent.generalSettingsSection + u'/screen blank',
+ self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'')).toString()
if not self.display.primary:
# Order done to handle initial conversion
@@ -744,8 +742,10 @@ class SlideController(QtGui.QWidget):
self.onThemeDisplay(True)
elif display_type == u'hidden':
self.onHideDisplay(True)
- else:
+ elif display_type == u'blanked':
self.onBlankDisplay(True)
+ else:
+ Receiver.send_message(u'maindisplay_show')
def onSlideBlank(self):
"""
@@ -772,11 +772,11 @@ class SlideController(QtGui.QWidget):
self.desktopScreen.setChecked(False)
if checked:
QtCore.QSettings().setValue(
- self.parent.generalSettingsSection + u'/screen blank',
+ self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'blanked'))
else:
QtCore.QSettings().remove(
- self.parent.generalSettingsSection + u'/screen blank')
+ self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin()
self.updatePreview()
@@ -793,11 +793,11 @@ class SlideController(QtGui.QWidget):
self.desktopScreen.setChecked(False)
if checked:
QtCore.QSettings().setValue(
- self.parent.generalSettingsSection + u'/screen blank',
+ self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'themed'))
else:
QtCore.QSettings().remove(
- self.parent.generalSettingsSection + u'/screen blank')
+ self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin()
self.updatePreview()
@@ -814,11 +814,11 @@ class SlideController(QtGui.QWidget):
self.desktopScreen.setChecked(checked)
if checked:
QtCore.QSettings().setValue(
- self.parent.generalSettingsSection + u'/screen blank',
+ self.parent().generalSettingsSection + u'/screen blank',
QtCore.QVariant(u'hidden'))
else:
QtCore.QSettings().remove(
- self.parent.generalSettingsSection + u'/screen blank')
+ self.parent().generalSettingsSection + u'/screen blank')
self.hidePlugin(checked)
self.updatePreview()
@@ -841,6 +841,11 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_unblank'
% self.serviceItem.name.lower(),
[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):
"""
@@ -859,6 +864,11 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_unblank'
% self.serviceItem.name.lower(),
[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):
"""
@@ -933,7 +943,7 @@ class SlideController(QtGui.QWidget):
rect.y(), rect.width(), rect.height())
self.slidePreview.setPixmap(winimg)
- def onSlideSelectedNext(self):
+ def onSlideSelectedNext(self, wrap=None):
"""
Go to the next slide.
"""
@@ -946,8 +956,11 @@ class SlideController(QtGui.QWidget):
else:
row = self.previewListWidget.currentRow() + 1
if row == self.previewListWidget.rowCount():
- if QtCore.QSettings().value(self.parent.generalSettingsSection +
- u'/enable slide loop', QtCore.QVariant(True)).toBool():
+ if wrap is None:
+ wrap = QtCore.QSettings().value(
+ self.parent().generalSettingsSection +
+ u'/enable slide loop', QtCore.QVariant(True)).toBool()
+ if wrap:
row = 0
else:
row = self.previewListWidget.rowCount() - 1
@@ -967,8 +980,8 @@ class SlideController(QtGui.QWidget):
else:
row = self.previewListWidget.currentRow() - 1
if row == -1:
- if QtCore.QSettings().value(self.parent.generalSettingsSection +
- u'/enable slide loop', QtCore.QVariant(True)).toBool():
+ if QtCore.QSettings().value(self.parent().generalSettingsSection
+ + u'/enable slide loop', QtCore.QVariant(True)).toBool():
row = self.previewListWidget.rowCount() - 1
else:
row = 0
@@ -996,11 +1009,11 @@ class SlideController(QtGui.QWidget):
self.previewListWidget.rowCount() - 1)
self.slideSelected()
- def onToggleLoop(self, toggled):
+ def onToggleLoop(self):
"""
Toggles the loop state.
"""
- if self.toolbar.actions[u'Start Loop'].isVisible():
+ if self.playSlidesLoop.isChecked() or self.playSlidesOnce.isChecked():
self.onStartLoop()
else:
self.onStopLoop()
@@ -1012,8 +1025,6 @@ class SlideController(QtGui.QWidget):
if self.previewListWidget.rowCount() > 1:
self.timer_id = self.startTimer(
int(self.delaySpinBox.value()) * 1000)
- self.toolbar.actions[u'Stop Loop'].setVisible(True)
- self.toolbar.actions[u'Start Loop'].setVisible(False)
def onStopLoop(self):
"""
@@ -1022,15 +1033,39 @@ class SlideController(QtGui.QWidget):
if self.timer_id != 0:
self.killTimer(self.timer_id)
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):
"""
If the timer event is for this window select next slide
"""
if event.timerId() == self.timer_id:
- self.onSlideSelectedNext()
+ self.onSlideSelectedNext(self.playSlidesLoop.isChecked())
def onEditSong(self):
"""
@@ -1044,7 +1079,9 @@ class SlideController(QtGui.QWidget):
"""
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):
"""
@@ -1072,7 +1109,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message('servicemanager_preview_live',
u'%s:%s' % (self.serviceItem._uuid, row))
else:
- self.parent.liveController.addServiceManagerItem(
+ self.parent().liveController.addServiceManagerItem(
self.serviceItem, row)
def onMediaStart(self, item):
diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py
index 4dabcfdf7..72bdf4558 100644
--- a/openlp/core/ui/thememanager.py
+++ b/openlp/core/ui/thememanager.py
@@ -57,8 +57,6 @@ class ThemeManager(QtGui.QWidget):
self.settingsSection = u'themes'
self.themeForm = ThemeForm(self)
self.fileRenameForm = FileRenameForm(self)
- self.serviceComboBox = \
- self.mainwindow.serviceManagerContents.themeComboBox
# start with the layout
self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0)
diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py
index 709b3ad80..7e8188f42 100644
--- a/openlp/core/ui/themestab.py
+++ b/openlp/core/ui/themestab.py
@@ -145,10 +145,8 @@ class ThemesTab(SettingsTab):
def save(self):
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
- settings.setValue(u'theme level',
- QtCore.QVariant(self.theme_level))
- settings.setValue(u'global theme',
- QtCore.QVariant(self.global_theme))
+ settings.setValue(u'theme level', QtCore.QVariant(self.theme_level))
+ settings.setValue(u'global theme', QtCore.QVariant(self.global_theme))
settings.endGroup()
self.mainwindow.renderer.set_global_theme(
self.global_theme, self.theme_level)
@@ -186,8 +184,7 @@ class ThemesTab(SettingsTab):
self.settingsSection + u'/global theme',
QtCore.QVariant(u'')).toString())
self.DefaultComboBox.clear()
- for theme in theme_list:
- self.DefaultComboBox.addItem(theme)
+ self.DefaultComboBox.addItems(theme_list)
find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
self.mainwindow.renderer.set_global_theme(
self.global_theme, self.theme_level)
diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py
index 4ef445e36..ec20346d8 100644
--- a/openlp/core/utils/__init__.py
+++ b/openlp/core/utils/__init__.py
@@ -69,7 +69,6 @@ class VersionThread(QtCore.QThread):
Run the thread.
"""
time.sleep(1)
- Receiver.send_message(u'maindisplay_blank_check')
app_version = get_application_version()
version = check_latest_version(app_version)
remote_version = {}
diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py
index 0c0a4ed56..475d0a47a 100644
--- a/openlp/core/utils/languagemanager.py
+++ b/openlp/core/utils/languagemanager.py
@@ -77,6 +77,8 @@ class LanguageManager(object):
AppLocation.LanguageDir))
file_names = trans_dir.entryList(QtCore.QStringList(u'*.qm'),
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:
file_names.replaceInStrings(name, trans_dir.filePath(name))
return file_names
diff --git a/openlp/plugins/alerts/forms/alertform.py b/openlp/plugins/alerts/forms/alertform.py
index 13cb4503a..1415c809c 100644
--- a/openlp/plugins/alerts/forms/alertform.py
+++ b/openlp/plugins/alerts/forms/alertform.py
@@ -41,7 +41,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
Initialise the alert form
"""
self.manager = plugin.manager
- self.parent = plugin
+ self.plugin = plugin
self.item_id = None
QtGui.QDialog.__init__(self, plugin.formparent)
self.setupUi(self)
@@ -195,7 +195,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.parameterEdit.setFocus()
return False
text = text.replace(u'<>', unicode(self.parameterEdit.text()))
- self.parent.alertsmanager.displayAlert(text)
+ self.plugin.alertsmanager.displayAlert(text)
return True
def onCurrentRowChanged(self, row):
diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py
index c55e76ef7..1d40d5dd3 100644
--- a/openlp/plugins/alerts/lib/alertsmanager.py
+++ b/openlp/plugins/alerts/lib/alertsmanager.py
@@ -40,8 +40,7 @@ class AlertsManager(QtCore.QObject):
log.info(u'Alert Manager loaded')
def __init__(self, parent):
- QtCore.QObject.__init__(self)
- self.parent = parent
+ QtCore.QObject.__init__(self, parent)
self.screen = None
self.timer_id = 0
self.alertList = []
@@ -85,8 +84,8 @@ class AlertsManager(QtCore.QObject):
if len(self.alertList) == 0:
return
text = self.alertList.pop(0)
- alertTab = self.parent.settings_tab
- self.parent.liveController.display.alert(text)
+ alertTab = self.parent().settings_tab
+ self.parent().liveController.display.alert(text)
# Check to see if we have a timer running.
if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
@@ -101,7 +100,7 @@ class AlertsManager(QtCore.QObject):
"""
log.debug(u'timer event')
if event.timerId() == self.timer_id:
- self.parent.liveController.display.alert(u'')
+ self.parent().liveController.display.alert(u'')
self.killTimer(self.timer_id)
self.timer_id = 0
self.generateAlert()
diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py
index 2deb86cc1..5d4f1bdb1 100644
--- a/openlp/plugins/bibles/bibleplugin.py
+++ b/openlp/plugins/bibles/bibleplugin.py
@@ -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.utils.actions import ActionList
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
+from openlp.plugins.bibles.forms import BibleUpgradeForm
log = logging.getLogger(__name__)
@@ -59,6 +60,8 @@ class BiblePlugin(Plugin):
#action_list.add_action(self.exportBibleItem, UiStrings().Export)
# Set to invisible until we can export bibles
self.exportBibleItem.setVisible(False)
+ if len(self.manager.old_bible_databases):
+ self.toolsUpgradeItem.setVisible(True)
def finalise(self):
"""
@@ -73,6 +76,19 @@ class BiblePlugin(Plugin):
#action_list.remove_action(self.exportBibleItem, UiStrings().Export)
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):
self.importBibleItem = base_action(import_menu, u'importBibleItem')
self.importBibleItem.setText(translate('BiblesPlugin', '&Bible'))
@@ -88,6 +104,39 @@ class BiblePlugin(Plugin):
export_menu.addAction(self.exportBibleItem)
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):
if self.mediaItem:
self.mediaItem.onImportClick()
@@ -149,4 +198,3 @@ class BiblePlugin(Plugin):
'Add the selected Bible to the service.')
}
self.setPluginUiTextStrings(tooltips)
-
diff --git a/openlp/plugins/bibles/forms/__init__.py b/openlp/plugins/bibles/forms/__init__.py
index 83b444394..58ed5fa88 100644
--- a/openlp/plugins/bibles/forms/__init__.py
+++ b/openlp/plugins/bibles/forms/__init__.py
@@ -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
from the .ui files later if necessary.
"""
-
+from booknameform import BookNameForm
+from languageform import LanguageForm
from bibleimportform import BibleImportForm
+from bibleupgradeform import BibleUpgradeForm
-__all__ = ['BibleImportForm']
+__all__ = [u'BookNameForm', u'LanguageForm', u'BibleImportForm',
+ u'BibleUpgradeForm']
diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py
index e05e29d57..367f1e1b3 100644
--- a/openlp/plugins/bibles/forms/bibleimportform.py
+++ b/openlp/plugins/bibles/forms/bibleimportform.py
@@ -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.utils import AppLocation, string_is_unicode
from openlp.plugins.bibles.lib.manager import BibleFormat
+from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
log = logging.getLogger(__name__)
@@ -125,9 +126,6 @@ class BibleImportForm(OpenLPWizard):
QtCore.QObject.connect(self.osisBrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onOsisBrowseButtonClicked)
- QtCore.QObject.connect(self.csvTestamentsButton,
- QtCore.SIGNAL(u'clicked()'),
- self.onCsvTestamentsBrowseButtonClicked)
QtCore.QObject.connect(self.csvBooksButton,
QtCore.SIGNAL(u'clicked()'),
self.onCsvBooksBrowseButtonClicked)
@@ -188,18 +186,6 @@ class BibleImportForm(OpenLPWizard):
self.csvLayout = QtGui.QFormLayout(self.csvWidget)
self.csvLayout.setMargin(0)
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.setObjectName(u'CsvBooksLabel')
self.csvBooksLayout = QtGui.QHBoxLayout()
@@ -384,8 +370,6 @@ class BibleImportForm(OpenLPWizard):
translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
self.osisFileLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
- self.csvTestamentsLabel.setText(
- translate('BiblesPlugin.ImportWizardForm', 'Testaments file:'))
self.csvBooksLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
self.csvVersesLabel.setText(
@@ -436,7 +420,6 @@ class BibleImportForm(OpenLPWizard):
# Align all QFormLayouts towards each other.
labelWidth = max(self.formatLabel.minimumSizeHint().width(),
self.osisFileLabel.minimumSizeHint().width(),
- self.csvTestamentsLabel.minimumSizeHint().width(),
self.csvBooksLabel.minimumSizeHint().width(),
self.csvVersesLabel.minimumSizeHint().width(),
self.openSongFileLabel.minimumSizeHint().width(),
@@ -458,14 +441,6 @@ class BibleImportForm(OpenLPWizard):
self.osisFileEdit.setFocus()
return False
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():
critical_error_message_box(UiStrings().NFSs,
translate('BiblesPlugin.ImportWizardForm',
@@ -498,6 +473,7 @@ class BibleImportForm(OpenLPWizard):
license_version = unicode(self.field(u'license_version').toString())
license_copyright = \
unicode(self.field(u'license_copyright').toString())
+ path = AppLocation.get_section_data_path(u'bibles')
if not license_version:
critical_error_message_box(UiStrings().EmptyField,
translate('BiblesPlugin.ImportWizardForm',
@@ -519,6 +495,15 @@ class BibleImportForm(OpenLPWizard):
'a different Bible or first delete the existing one.'))
self.versionNameEdit.setFocus()
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
if self.currentPage() == self.progressPage:
return True
@@ -543,14 +528,6 @@ class BibleImportForm(OpenLPWizard):
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OSIS,
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):
"""
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'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_versefile', self.csvVersesEdit)
self.selectPage.registerField(u'opensong_file', self.openSongFileEdit)
@@ -619,7 +594,6 @@ class BibleImportForm(OpenLPWizard):
self.cancelButton.setVisible(True)
self.setField(u'source_format', QtCore.QVariant(0))
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_versefile', 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.
"""
- filepath = AppLocation.get_directory(AppLocation.PluginsDir)
- filepath = os.path.join(filepath, u'bibles', u'resources')
# Load Crosswalk Bibles.
- self.loadBibleResourceFile(
- os.path.join(filepath, u'crosswalkbooks.csv'),
- WebDownload.Crosswalk)
+ self.loadBibleResource(WebDownload.Crosswalk)
# Load BibleGateway Bibles.
- self.loadBibleResourceFile(os.path.join(filepath, u'biblegateway.csv'),
- WebDownload.BibleGateway)
+ self.loadBibleResource(WebDownload.BibleGateway)
# Load and Bibleserver Bibles.
- self.loadBibleResourceFile(os.path.join(filepath, u'bibleserver.csv'),
- WebDownload.Bibleserver)
+ self.loadBibleResource(WebDownload.Bibleserver)
- def loadBibleResourceFile(self, file_path_name, download_type):
+ def loadBibleResource(self, download_type):
"""
- Loads a web bible resource file.
-
- ``file_path_name``
- The file to load including the file's path.
+ Loads a web bible from bible_resources.sqlite.
``download_type``
- The WebDownload type this file is for.
+ The WebDownload type e.g. bibleserver.
"""
self.web_bible_list[download_type] = {}
- books_file = None
- 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])
- finally:
- if books_file:
- books_file.close()
+ bibles = BiblesResourcesDB.get_webbibles(
+ WebDownload.Names[download_type])
+ for bible in bibles:
+ version = bible[u'name']
+ name = bible[u'abbreviation']
+ self.web_bible_list[download_type][version] = name.strip()
def preWizard(self):
"""
@@ -720,8 +675,7 @@ class BibleImportForm(OpenLPWizard):
elif bible_type == BibleFormat.CSV:
# Import a CSV bible.
importer = self.manager.import_bible(BibleFormat.CSV,
- name=license_version, testamentsfile=unicode(
- self.field(u'csv_testamentsfile').toString()),
+ name=license_version,
booksfile=unicode(self.field(u'csv_booksfile').toString()),
versefile=unicode(self.field(u'csv_versefile').toString())
)
@@ -752,7 +706,7 @@ class BibleImportForm(OpenLPWizard):
name=license_version,
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,
license_copyright, license_permissions)
self.manager.reload_bibles()
diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py
new file mode 100644
index 000000000..7913aac31
--- /dev/null
+++ b/openlp/plugins/bibles/forms/bibleupgradeform.py
@@ -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 Frequently Asked Questions.'))
+ 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)
diff --git a/openlp/plugins/bibles/forms/booknamedialog.py b/openlp/plugins/bibles/forms/booknamedialog.py
new file mode 100644
index 000000000..e9211b3d5
--- /dev/null
+++ b/openlp/plugins/bibles/forms/booknamedialog.py
@@ -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'))
diff --git a/openlp/plugins/bibles/forms/booknameform.py b/openlp/plugins/bibles/forms/booknameform.py
new file mode 100644
index 000000000..b07f28bf1
--- /dev/null
+++ b/openlp/plugins/bibles/forms/booknameform.py
@@ -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)
diff --git a/openlp/plugins/bibles/forms/languagedialog.py b/openlp/plugins/bibles/forms/languagedialog.py
new file mode 100644
index 000000000..5c1325a54
--- /dev/null
+++ b/openlp/plugins/bibles/forms/languagedialog.py
@@ -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:'))
diff --git a/openlp/plugins/bibles/forms/languageform.py b/openlp/plugins/bibles/forms/languageform.py
new file mode 100644
index 000000000..477c7ee1e
--- /dev/null
+++ b/openlp/plugins/bibles/forms/languageform.py
@@ -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)
diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py
index 37764108a..fe72f1bfd 100644
--- a/openlp/plugins/bibles/lib/csvbible.py
+++ b/openlp/plugins/bibles/lib/csvbible.py
@@ -71,7 +71,7 @@ import chardet
import csv
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__)
@@ -79,6 +79,8 @@ class CSVBible(BibleDB):
"""
This class provides a specialisation for importing of CSV Bibles.
"""
+ log.info(u'CSVBible loaded')
+
def __init__(self, parent, **kwargs):
"""
Loads a Bible from a set of CVS files.
@@ -87,48 +89,10 @@ class CSVBible(BibleDB):
"""
log.info(self.__class__.__name__)
BibleDB.__init__(self, parent, **kwargs)
- try:
- self.testamentsfile = kwargs[u'testamentsfile']
- except KeyError:
- self.testamentsfile = None
self.booksfile = kwargs[u'booksfile']
self.versesfile = kwargs[u'versefile']
- def setup_testaments(self):
- """
- 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):
+ def do_import(self, bible_name=None):
"""
Import the bible books and verses.
"""
@@ -136,6 +100,10 @@ class CSVBible(BibleDB):
self.wizard.progressBar.setMinimum(0)
self.wizard.progressBar.setMaximum(66)
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
book_list = {}
# Populate the Tables
@@ -149,8 +117,15 @@ class CSVBible(BibleDB):
self.wizard.incrementProgressBar(unicode(
translate('BibleDB.Wizard', 'Importing books... %s')) %
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']),
- 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'])
Receiver.send_message(u'openlp_process_events')
except (IOError, IndexError):
diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py
index c896528ea..41dc947f9 100644
--- a/openlp/plugins/bibles/lib/db.py
+++ b/openlp/plugins/bibles/lib/db.py
@@ -27,16 +27,19 @@
import logging
import chardet
+import os
import re
+import sqlite3
from PyQt4 import QtCore
from sqlalchemy import Column, ForeignKey, or_, Table, types
from sqlalchemy.orm import class_mapper, mapper, relation
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.ui import critical_error_message_box
+from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
@@ -47,13 +50,6 @@ class BibleMeta(BaseModel):
pass
-class Testament(BaseModel):
- """
- Bible Testaments
- """
- pass
-
-
class Book(BaseModel):
"""
Song model
@@ -67,6 +63,18 @@ class Verse(BaseModel):
"""
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):
"""
@@ -81,19 +89,17 @@ def init_schema(url):
Column(u'key', types.Unicode(255), primary_key=True, index=True),
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,
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'abbreviation', types.Unicode(5), index=True),
)
verse_table = Table(u'verse', metadata,
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'verse', types.Integer, index=True),
Column(u'text', types.UnicodeText, index=True),
@@ -103,11 +109,6 @@ def init_schema(url):
class_mapper(BibleMeta)
except UnmappedClassError:
mapper(BibleMeta, meta_table)
- try:
- class_mapper(Testament)
- except UnmappedClassError:
- mapper(Testament, testament_table,
- properties={'books': relation(Book, backref='testament')})
try:
class_mapper(Book)
except UnmappedClassError:
@@ -129,6 +130,7 @@ class BibleDB(QtCore.QObject, Manager):
methods, but benefit from the database methods in here via inheritance,
rather than depending on yet another object.
"""
+ log.info(u'BibleDB loaded')
def __init__(self, parent, **kwargs):
"""
@@ -156,12 +158,14 @@ class BibleDB(QtCore.QObject, Manager):
self.name = kwargs[u'name']
if not isinstance(self.name, unicode):
self.name = unicode(self.name, u'utf-8')
- self.file = self.clean_filename(self.name)
+ self.file = clean_filename(self.name)
if u'file' in kwargs:
self.file = kwargs[u'file']
Manager.__init__(self, u'bibles', init_schema, self.file)
if u'file' in kwargs:
self.get_name()
+ if u'path' in kwargs:
+ self.path = kwargs[u'path']
self.wizard = None
QtCore.QObject.connect(Receiver.get_receiver(),
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
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):
"""
This method basically just initialialises the database. It is called
@@ -206,36 +197,40 @@ class BibleDB(QtCore.QObject, Manager):
"""
self.wizard = wizard
self.create_meta(u'dbversion', u'2')
- self.setup_testaments()
return self.name
- def setup_testaments(self):
- """
- 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):
+ def create_book(self, name, bk_ref_id, testament=1):
"""
Add a book to the database.
``name``
The name of the book.
- ``abbrev``
- The abbreviation of the book.
+ ``bk_ref_id``
+ The book_reference_id from bibles_resources.sqlite of the book.
``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)
- book = Book.populate(name=name, abbreviation=abbrev,
- testament_id=testament)
+ log.debug(u'BibleDB.create_book("%s", "%s")', name, bk_ref_id)
+ book = Book.populate(name=name, book_reference_id=bk_ref_id,
+ testament_reference_id=testament)
self.save_object(book)
return book
+ 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):
"""
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,
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.
for verse_number, verse_text in textlist.iteritems():
verse = Verse.populate(
@@ -300,7 +295,9 @@ class BibleDB(QtCore.QObject, Manager):
``value``
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))
def get_book(self, book):
@@ -310,20 +307,60 @@ class BibleDB(QtCore.QObject, Manager):
``book``
The name of the book to return.
"""
- log.debug(u'BibleDb.get_book("%s")', book)
- db_book = 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
+ log.debug(u'BibleDB.get_book("%s")', book)
+ return self.get_object_filtered(Book, Book.name.like(book + u'%'))
def get_books(self):
"""
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.
"""
+ log.debug(u'BibleDB.get_books()')
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):
"""
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
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
them up into references like this, bundle them into a list. This
function then runs through the list, and returns an amalgamated
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 = []
- for book, chapter, start_verse, end_verse in reference_list:
- db_book = self.get_book(book)
+ book_error = False
+ for book_id, chapter, start_verse, end_verse in reference_list:
+ db_book = self.get_book_by_book_ref_id(book_id)
if db_book:
- book = db_book.name
- log.debug(u'Book name corrected to "%s"', book)
+ book_id = db_book.book_reference_id
+ log.debug(u'Book name corrected to "%s"', db_book.name)
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)\
.filter_by(book_id=db_book.id)\
.filter_by(chapter=chapter)\
@@ -360,13 +398,14 @@ class BibleDB(QtCore.QObject, Manager):
.all()
verse_list.extend(verses)
else:
- log.debug(u'OpenLP failed to find book %s', book)
- if show_error:
- 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.'))
+ log.debug(u'OpenLP failed to find book with id "%s"', book_id)
+ book_error = True
+ if book_error and show_error:
+ 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.'))
return verse_list
def verse_search(self, text):
@@ -399,18 +438,18 @@ class BibleDB(QtCore.QObject, Manager):
Return the number of chapters in a 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)\
- .filter(Book.name == book)\
+ .filter(Book.book_reference_id==book.book_reference_id)\
.distinct().count()
if not count:
return 0
else:
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.
@@ -420,16 +459,49 @@ class BibleDB(QtCore.QObject, Manager):
``chapter``
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)\
- .filter(Book.name == book)\
- .filter(Verse.chapter == chapter)\
+ .filter(Book.book_reference_id==book_id)\
+ .filter(Verse.chapter==chapter)\
.count()
if not count:
return 0
else:
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):
"""
Utility debugging method to dump the contents of a bible.
@@ -441,3 +513,591 @@ class BibleDB(QtCore.QObject, Manager):
log.debug(u'...............................Verses ')
verses = self.session.query(Verse).all()
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
diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py
index b66aa0373..76a99ea50 100644
--- a/openlp/plugins/bibles/lib/http.py
+++ b/openlp/plugins/bibles/lib/http.py
@@ -42,161 +42,26 @@ from openlp.core.lib import Receiver, translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import AppLocation, get_web_page
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__)
-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):
"""
Extract verses from BibleGateway
"""
def __init__(self, proxyurl=None):
- log.debug(u'init %s', proxyurl)
+ log.debug(u'BGExtract.init("%s")', proxyurl)
self.proxyurl = proxyurl
socket.setdefaulttimeout(30)
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``
- The version of the bible like 31 for New International version.
+ The version of the Bible like 31 for New International version.
``bookname``
Name of the Book.
@@ -204,10 +69,11 @@ class BGExtract(object):
``chapter``
Chapter number.
"""
- log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter)
- url_params = urllib.urlencode(
- {u'search': u'%s %s' % (bookname, chapter),
- u'version': u'%s' % version})
+ log.debug(u'BGExtract.get_bible_chapter("%s", "%s", "%s")', version,
+ bookname, chapter)
+ urlbookname = urllib.quote(bookname.encode("utf-8"))
+ url_params = u'search=%s+%s&version=%s' % (urlbookname, chapter,
+ version)
cleaner = [(re.compile(' |
|\'\+\''), lambda match: '')]
soup = get_soup_for_bible_ref(
u'http://www.biblegateway.com/passage/?%s' % url_params,
@@ -230,10 +96,10 @@ class BGExtract(object):
verse_list = {}
# Cater for inconsistent mark up in the first verse of a chapter.
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])
for verse in verses(u'sup', u'versenum'):
- raw_verse_num = verse.next
+ raw_verse_num = verse.next
clean_verse_num = 0
# Not all verses exist in all translations and may or may not be
# represented by a verse number. If they are not fine, if they are
@@ -243,7 +109,7 @@ class BGExtract(object):
try:
clean_verse_num = int(str(raw_verse_num))
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))
if clean_verse_num:
verse_text = raw_verse_num.next
@@ -264,13 +130,60 @@ class BGExtract(object):
return None
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'